2016-03-14 3 views
2

Я готовлю некоторые данные для когортного анализа. Информация у меня похожа на фальшивый набор данных, которые могут быть сгенерированы на код ниже: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.

ответ

1

Да, есть:

df['rev_period'] = df['invoice_date'] + pd.offsets.MonthEnd(0) 

Должно быть, по крайней мере, на порядок быстрее.