Преобразование месяца в квартал в датафрейме Python
У меня в столбце данных есть столбец, обозначающий месяц (в форме yyyy-mm
). Я хочу преобразовать это в четверть, используя pd.Period
, Я попытался использовать функцию применения в форме ниже, но она работает слишком медленно. Есть лучший способ сделать это? Я использую:
hp2['Qtr'] = hp2.apply(lambda x: pd.Period(x['Mth'],'Q'),axis=1)
4 ответа
Я бы использовал метод to_datetime() в векторизованном виде:
In [76]: x
Out[76]:
Month
0 2016-11
1 2011-01
2 2015-07
3 2012-09
In [77]: x['Qtr'] = pd.to_datetime(x.Month).dt.quarter
In [78]: x
Out[78]:
Month Qtr
0 2016-11 4
1 2011-01 1
2 2015-07 3
3 2012-09 3
Или если вы хотите иметь его в 2016Q4
формат (как упомянуто @root), используя PeriodIndex()
:
In [114]: x['Qtr'] = pd.PeriodIndex(pd.to_datetime(x.Mth), freq='Q')
In [115]: x
Out[115]:
Mth Qtr
0 2016-11 2016Q4
1 2011-01 2011Q1
2 2015-07 2015Q3
3 2012-09 2012Q3
Поскольку вам не нужна вся строка, будет ли быстрее, если вы отобразите значения из одного столбца?
hp2['Qtr'] = hp2['Mth'].map(lambda x: pd.Period(x,'Q'))
Та же идея, что и у @MaxU, но с использованием astype
:
hp2['Qtr'] = pd.to_datetime(hp2['Mth'].values, format='%Y-%m').astype('period[Q]')
Полученный результат:
Mth Qtr
0 2014-01 2014Q1
1 2017-02 2017Q1
2 2016-03 2016Q1
3 2017-04 2017Q2
4 2016-05 2016Q2
5 2016-06 2016Q2
6 2017-07 2017Q3
7 2016-08 2016Q3
8 2017-09 2017Q3
9 2015-10 2015Q4
10 2017-11 2017Q4
11 2015-12 2015Q4
Задержки
Используя следующую настройку, вы получите большой набор данных:
n = 10**5
yrs = np.random.choice(range(2010, 2021), n)
mths = np.random.choice(range(1, 13), n)
df = pd.DataFrame({'Mth': ['{0}-{1:02d}'.format(*p) for p in zip(yrs, mths)]})
Я получаю следующие сроки:
%timeit pd.to_datetime(df['Mth'].values, format='%Y-%m').astype('period[Q]')
10 loops, best of 3: 33.4 ms per loop
%timeit pd.PeriodIndex(pd.to_datetime(df.Mth), freq='Q')
1 loop, best of 3: 2.68 s per loop
%timeit df['Mth'].map(lambda x: pd.Period(x,'Q'))
1 loop, best of 3: 6.26 s per loop
%timeit df.apply(lambda x: pd.Period(x['Mth'],'Q'),axis=1)
1 loop, best of 3: 9.49 s per loop
Я работаю над df, который содержит 9994 строки, поэтому я проверил ваш код на соответствие тому, что использовал в прошлом, и опубликовал результаты для вас. Вот пример df, не совсем YYYY-MM, но это не имеет значения, потому что код будет работать либо:
hp2['Mth'][:10]
Out[11]:
0 2016-06-26
1 2016-06-26
2 2016-06-26
3 2016-06-26
4 2016-06-26
5 2016-06-26
6 2016-06-26
7 2016-06-26
8 2016-06-26
9 2016-06-26
Name: Mth, dtype: datetime64[ns]
Я запустил ваш код на моем DF:
%timeit hp2['Qtr_Period']= hp2.apply(lambda x: pd.Period(x['Mth'],'Q'), axis=1)
hp2['Qtr_Period'][:10]
1 loop, best of 3: 2.28 s per loop
Out[13]:
0 2016Q2
1 2016Q2
2 2016Q2
3 2016Q2
4 2016Q2
5 2016Q2
6 2016Q2
7 2016Q2
8 2016Q2
9 2016Q2
Name: Qtr_Period, dtype: object
Затем я проверил это с помощью этого:
%timeit hp2['Qtr_dt']= (df['Order Date'].dt.year.astype(str))+'Q'+(df['Order Date'].dt.quarter.astype(str))
hp2['Qtr_dt'][:10]
10 loops, best of 3: 67.6 ms per loop
Out[14]:
0 2016Q2
1 2016Q2
2 2016Q2
3 2016Q2
4 2016Q2
5 2016Q2
6 2016Q2
7 2016Q2
8 2016Q2
9 2016Q2
Name: Qtr_dt, dtype: object
Это ясно из результатов. Надеюсь, это поможет. Вы можете найти больше информации на pandas.Series.dt
month = ['2016-11', '2011-01', '2015-06', '2012-09']
x = pd.DataFrame(month, columns=["month"])
x.month = pd.to_datetime(x.month)
x['quarter'] = [pd.Period(x.month[i], freq='M').quarter for i in range(len(x))]
x
month quarter
0 2016-11-01 4
1 2011-01-01 1
2 2015-06-01 2
3 2012-09-01 3