Я готовлю некоторые данные для когортного анализа. Информация у меня похожа на фальшивый набор данных, которые могут быть сгенерированы на код ниже:Pandas: более быстрый метод, чем повторение транзакций?
import random
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
# prepare some fake data to build frames
subscription_prices = [x - 0.05 for x in range(100, 500, 25)]
companies = ['initech','ingen','weyland','tyrell']
starting_periods = ['2014-12-10','2015-1-15','2014-11-20','2015-2-9']
# use the lists and dict from above to create a fake dataset
pieces = []
for company, period in zip(companies,starting_periods):
data = {
'company': company,
'revenue': random.choice(subscription_prices),
'invoice_date': pd.date_range(period,periods=12,freq='31D')
}
frame = DataFrame(data)
pieces.append(frame)
df = pd.concat(pieces, ignore_index=True)
мне нужно нормализовать дату счета-фактуры в месячный срок. По ряду причин лучше всего переместить все значения invoice_date
до конца месяца. Я использовал этот метод:
from pandas.tseries.offsets import *
df['rev_period'] = df['invoice_date'].apply(lambda x: MonthEnd(normalize=True).rollforward(x))
Однако, даже при только миллион строк (что размер моего фактического набора данных) это становится мучительно медленно:
In [11]: %time df['invoice_date'].apply(lambda x: MonthEnd(normalize=True).rollforward(x))
CPU times: user 3min 11s, sys: 1.44 s, total: 3min 12s
Wall time: 3min 17s
Большая часть этого метода date offsetting w/Pandas заключается в том, что если invoice_date
выпадает на последний день месяца, эта дата останется в качестве последнего дня месяца. Другая приятная вещь заключается в том, что это сохраняет dtype
как datetime
, тогда как df['invoice_date'].apply(lambda x: x.strftime('%Y-%m'))
быстрее, но преобразует значения в str
.
Есть ли векторизованный способ сделать это? Я попробовал MonthEnd(normalize=True).rollforward(df['invoice_date'])
, но получил ошибку TypeError: Cannot convert input to Timestamp
.