python 优化pandas group

Posted

技术标签:

【中文标题】python 优化pandas group【英文标题】:Optimizing pandas groupby python 【发布时间】:2017-07-25 11:32:53 【问题描述】:

我有一个包含产品合同的数据框(带有Product_ID)。这些合约在特定日期打开(StartDate)并在特定时间关闭(CloseDate)。合同也有可能在此时处于活动状态,因此没有 CloseDate。

有多个客户有合同,由ID 引用。这些客户在特定时间填写调查,该时间由日期(Key_Date)表示。

我要计算的是几个特征,但是对于这个例子,我将重点关注独特产品的数量。我想知道某个客户在填写调查表时有多少独特的产品。

我们有一个数据框df_result,其中包含客户的 ID 和他们填写调查问卷的日期。在这个数据框中,我们还将附加计算的特征:

import pandas as pd
import numpy as np
np.random.seed(256)
df_result = pd.DataFrame('ID' : np.random.randint(3, size=(10)),
                      'Key_Date' : pd.date_range(start=pd.datetime(2015, 5, 21), periods=10, freq='m'))
df_result.head()

    ID  Key_Date
0   0   2015-05-31
1   2   2015-06-30
2   1   2015-07-31
3   0   2015-08-31
4   1   2015-09-30

我们还有一个包含不同合同/产品的数据框,名为df_products

np.random.seed(321)
df_products = pd.DataFrame('ID' : np.random.randint(5, size=(10)),
                        'Product_ID' : np.random.randint(low = 101, high = 104, size=10),
                      'StartDate' : pd.date_range(start=pd.datetime(2015, 3, 1), periods=10, freq='m'),
                       'CloseDate' : pd.date_range(start=pd.datetime(2016, 1, 1), periods=10, freq='m'))
df_products.head()

    CloseDate   StartDate   ID  Product_ID
0   2016-01-31  2015-03-31  4   102
1   2016-02-29  2015-04-30  2   101
2   2016-03-31  2015-05-31  4   102
3   2016-04-30  2015-06-30  1   102
4   2016-05-31  2015-07-31  0   103

我做了一个功能来统计填写调查的客户的独特产品,其中合同在填写时仍然有效,key_date(所以合同的开始日期(StartDate)在此日期之前,结束日期 (CloseDate) 在此日期之后)。我还希望能够在填写日期之前给出一个范围,例如在过去一年中活跃的所有独特产品。因此,即使是 11 个月前的已关闭合约也将包括在内。为此,我给出了一个额外的参数timeperiod,我减去了填写日期(创建一个新日期:low_date)。然后,CloseDate 必须晚于low_date,而不是key_date

def unique_products(df,timeperiod,ID,key_date):
    low_date = key_date - relativedelta(months=timeperiod)
    data = df.loc[(df['StartDate'] <= key_date) & 
                  (df['CloseDate'] >= low_date) &
              (df['ID'] == ID)].groupby(['ID'], as_index = False)['Product_ID'].nunique().reset_index()
    if 'Product_ID' in list(data):
        try:
            return float(data['Product_ID'])
        except:
            return np.nan

在此之后,我将这些值附加到 df_result 中名为 unique_products 的新列中:

df_result['unique_products'] = df_result.apply(lambda row: unique_products(df_products, 3, row['ID'], row['Key_Date']), axis=1)
df_result.head()


    ID  Key_Date    unique_products
0   0   2015-05-31  NaN
1   2   2015-06-30  1.0
2   1   2015-07-31  1.0
3   0   2015-08-31  1.0
4   1   2015-09-30  2.0

但是,当将其应用于我的整个日期集时,由于每个调查行的时间不同,因此必须对其进行评估,因此速度会变得非常慢。有什么办法可以改善吗?

感谢您的任何意见:)

【问题讨论】:

【参考方案1】:

你需要使用合并。

merged = pd.merged(df_products,df_results,how='left',on='ID')

现在合并后将包含 df_products 的所有列以及“关键日期”,如果为 null,则此人尚未填写调查表。

filled_survey = merged.loc[~(merged['Key Date'].isnull())]

现在您可以通过减去相关日期并进行相应过滤来找到时间增量。

【讨论】:

【参考方案2】:
df_result['low_date'] = df_result['key_date'] - relativedelta(months=timeperiod) #creating low_date column
df_result2 = pandas.merge(df_result,df_products,how = "outer",on = "ID") #Join both the tables
df_result2 = df_result2[(df_result2['StartDate'] <= df_result2['key_date']) & (df_result2['CloseDate'] >= df_result2['low_date'])] # Filter conditions
df_result2 = df_result2.groupby(['ID','Key_Date'])['Product_ID'].nunique().reset_index()

使用交叉连接而不是您正在使用的循环尝试一次。

【讨论】:

以上是关于python 优化pandas group的主要内容,如果未能解决你的问题,请参考以下文章

python 优化pandas group

优化Python编程的4个妙招

我希望使用 lambda 和 pandas 使用 pythonic 方式优化代码

pandas优化

python数据分析之DataFrame内存优化

python数据分析之DataFrame内存优化