У меня есть набор данных под названием погода, и он содержит один столбец «Дата», который выглядит следующим образом.
Проблема в том, что год всегда 2020, хотя должен быть 2020, 2021 и 2022.
Нужный столбец выглядит так
Последний месяц каждого года не обязательно равен 12, но новый год начинается с месяца 01.
Вот мой код:
month = ['01','02','03','04','05','06','07','08','09','10','11','12']
for i in range(len(weather['Date'])):
year = 2022
for j in range(len(month)):
if weather['Date'][i][5:7] == '01':
weather['Date'][i] = weather['Date'][i].apply(lambda x: 'year' + x[5:])
Есть ли какие-либо предложения по исправлению моего кода и получению желаемого столбца?
Вы имеете в виду year += 1?
@AminS Спасибо, что указали на это! Нет, для каждого месяца есть несколько строк, и я изменил свой вопрос.
@Sheldon Да, это должен быть год += 1. Но для каждого месяца есть несколько строк, и, похоже, это не работает.
Вот один подход:
Date
в дату и время, используя pd.to_datetime и примените Series.diff и цепочку Series.dt.day.Series
будет представлять начало нового года, давайте применим Series.lt(0), чтобы превратить все значения ниже 0
в True
, а остальные в False
.Series
, содержащее 0, ..., 1, ..., 2
. Это будут значения, которые нужно добавить к году 2020
, чтобы получить правильные годы.(new_year = year + addition), month, day
в pd.to_datetime
(см. этот ТАК ответ).df['Date'] = pd.to_datetime(df['Date'])
df['Date'] = pd.to_datetime(dict(year=(df['Date'].dt.year
+ df['Date'].diff().dt.days.lt(0).cumsum()),
month=df['Date'].dt.month,
day=df['Date'].dt.day))
df['Date']
0 2020-01-01
1 2020-01-02
2 2020-02-01
3 2020-02-04
4 2020-03-01
5 2020-04-01
6 2020-04-02
7 2020-04-03
8 2020-04-04
9 2020-05-01
10 2020-06-01
11 2020-07-01
12 2020-08-01
13 2020-09-01
14 2020-10-01
15 2020-11-01
16 2021-01-01
17 2021-02-01
18 2021-04-01
19 2021-05-01
20 2021-06-01
21 2021-07-01
22 2021-08-01
23 2021-09-01
24 2021-10-01
25 2021-11-01
26 2021-12-01
27 2022-01-01
Name: Date, dtype: datetime64[ns]
Конечно, вам не нужно конвертировать в datetime. Вы также можете воссоздать строки даты, оставив следующую строку:
df['Date'].str[5:7].astype(int).diff().lt(0).cumsum()
Аналогично @ouroboros1, но с использованием numpy, чтобы получить количество лет, которое нужно добавить к каждой дате, а затем pd.offsets.DateOffset(years=...) для добавления.
import numpy as np
import pandas as pd
df['Date'] = pd.to_datetime(df['Date'])
s = df['Date'].values
y = np.r_[0, (s[:-1] > s[1:]).cumsum()]
На этом этапе было бы заманчиво сделать:
df['Date'] += y * pd.offsets.DateOffset(years=1)
Но тогда мы получим предупреждение: PerformanceWarning: Adding/subtracting object-dtype array to DatetimeArray not vectorized.
Поэтому вместо этого мы группируем по количеству лет для добавления и добавляем соответствующее смещение ко всем датам в группе.
def add_years(g):
return g['Date'] + pd.offsets.DateOffset(years=g['y'].iloc[0])
df['Date'] = df.assign(y=y).groupby('y', sort=False, group_keys=False).apply(add_years)
Это достаточно быстро (4,25 мс для 1000 строк и 10 различных значений y) и для других ситуаций, отличных от вашей, немного более общее, чем ответ @ouroboros1:
dt = df['Date'].dt; pd.to_datetime(dict(year=dt.year + y, month=dt.month, ...)
, тогда мы получим ValueError: cannot assemble the datetimes: day is out of range for month
).
У вас есть одна строка данных за каждый месяц с 1 января 2020 года?