Python Pandas Advanced:如何为在5天内至少购买了两次的客户获得结果?

Python Pandas Advanced:如何为在5天内至少购买了两次的客户获得结果?,python,pandas,Python,Pandas,我已经试着解决一个问题好几个小时了,并且一直坚持下去。以下是问题提纲: 将numpy导入为np 作为pd进口熊猫 df=pd.DataFrame({'orderid':[10315、10318、10321、10473、10621、10253、10541、10645], '客户ID':['ISLAT','ISLAT','ISLAT','ISLAT','ISLAT','HANAR','HANAR','HANAR'], ‘订购日期’:[‘1996-09-26’、‘1996-10-01’、‘1996-1

我已经试着解决一个问题好几个小时了,并且一直坚持下去。以下是问题提纲:

将numpy导入为np
作为pd进口熊猫
df=pd.DataFrame({'orderid':[10315、10318、10321、10473、10621、10253、10541、10645],
'客户ID':['ISLAT','ISLAT','ISLAT','ISLAT','ISLAT','HANAR','HANAR','HANAR'],
‘订购日期’:[‘1996-09-26’、‘1996-10-01’、‘1996-10-03’、‘1997-03-13’、‘1997-08-05’、‘1996-07-10’、‘1997-05-19’、‘1997-08-26’])
df
orderid customerid orderdate
0 10315 ISLAT 1996-09-26
110318 ISLAT 1996-10-01
210321 ISLAT 1996-10-03
310473 ISLAT 1997-03-13
410621群岛1997-08-05
510253 HANAR 1996-07-10
610541哈纳尔1997-05-19
7 10645 HANAR 1997-08-26
我想选择所有在5天内订购物品不止一次的客户

例如,这里只有客户在5天内订购,并且他已经订购了两次

我希望获得以下格式的输出:

所需输出
首先,要能够以天为单位计算差异,请转换orderdate 列到日期时间:

然后定义以下函数:

def fn(grp):
    return grp[(grp.orderdate.shift(-1) - grp.orderdate) / np.timedelta64(1, 'D') <= 5]

您可以使用
sort\u值和
diff
创建列“daysbetween”。在获得以下顺序后,您可以根据每个客户ID和所有数据将df与df连接一次
groupby
。最后,
query
在满足“daysbetween\u next”天数的情况下:

df['daysbetween'] = df.sort_values(['customerid', 'orderdate'])['orderdate'].diff().dt.days
df_final = df.join(df.groupby('customerid').shift(-1), 
                   lsuffix='_initial', rsuffix='_next')\
             .drop('daysbetween_initial', axis=1)\
             .query('daysbetween_next <= 5 and daysbetween_next >=0')
df['daysbetween']=df.sort_值(['customerid','orderdate'])['orderdate'].diff().dt.days
df_final=df.join(df.groupby('customerid').shift(-1),
lsuffix=''首字母,rsuffix=''下一个')\
.drop('daysbetween_initial',axis=1)\
.query('daysbetween\u next=0')

这很简单。让我们一次一个地写下需求,并试着以此为基础

首先,我想客户有一个唯一的id,因为它没有指定。我们将使用该id识别客户

第二,我假设客户在购买之前或之后5天购买并不重要

我的解决方案是使用一个简单的过滤器。请注意,此解决方案也可以在SQL数据库中实现

作为一个条件,我们要求用户是相同的。我们可以通过以下方式实现这一目标:

new_df = df[df["ID"] == df["ID"].shift(1)]
我们创建了一个新的数据帧,即new_df,其中包含所有行,以便第XT行与第xth-1行(即前一行)具有相同的用户id

现在,让我们通过在前一段代码中添加条件来搜索5天内的购买

new_df = df[df["ID"] == df["ID"].shift(1) & (df["Date"] - df["Date"].shift(1)) <= 5]

new_df=df[df[“ID”]==df[“ID”].shift(1)和(df[“Date”]-df[“Date”].shift(1))这有点棘手,因为在5天的窗口内可以有任意数量的购买对。这是利用
合并asof
的一个很好的用例,它允许对数据帧进行近似但不精确的匹配

输入数据

import pandas as pd
df = pd.DataFrame({'orderid': [10315, 10318, 10321, 10473, 10621, 10253, 10541, 10645],
          'customerid': ['ISLAT', 'ISLAT', 'ISLAT', 'ISLAT', 'ISLAT', 'HANAR', 'HANAR', 'HANAR'],
          'orderdate': ['1996-09-26', '1996-10-01', '1996-10-03', '1997-03-13', '1997-08-05', '1996-07-10', '1997-05-19', '1997-08-26']})
定义一个函数,根据给定的客户数据计算购买对

def compute_purchase_pairs(df):
    # Approximate self join on the date, but not exact.
    df_combined = pd.merge_asof(df,df, left_index=True, right_index=True,
                                suffixes=('_first', '_second') , allow_exact_matches=False)
    # Compute difference
    df_combined['timedelta'] = df_combined['orderdate_first'] - df_combined['orderdate_second']
    return df_combined
进行预处理并计算对

# Convert to datetime
df['orderdate'] = pd.to_datetime(df['orderdate'])
# Sort dataframe from last buy to newest (groupby will not change this order)
df2 = df.sort_values(by='orderdate', ascending=False)
# Create an index for joining
df2 = df.set_index('orderdate', drop=False)

# Compute puchases pairs for each customer
df_differences = df2.groupby('customerid').apply(compute_purchase_pairs)
# Show only the ones we care about
result = df_differences[df_differences['timedelta'].dt.days<=5]
result.reset_index(drop=True)
import pandas as pd
df = pd.DataFrame({'orderid': [10315, 10318, 10321, 10473, 10621, 10253, 10541, 10645],
          'customerid': ['ISLAT', 'ISLAT', 'ISLAT', 'ISLAT', 'ISLAT', 'HANAR', 'HANAR', 'HANAR'],
          'orderdate': ['1996-09-26', '1996-10-01', '1996-10-03', '1997-03-13', '1997-08-05', '1996-07-10', '1997-05-19', '1997-08-26']})
def compute_purchase_pairs(df):
    # Approximate self join on the date, but not exact.
    df_combined = pd.merge_asof(df,df, left_index=True, right_index=True,
                                suffixes=('_first', '_second') , allow_exact_matches=False)
    # Compute difference
    df_combined['timedelta'] = df_combined['orderdate_first'] - df_combined['orderdate_second']
    return df_combined
# Convert to datetime
df['orderdate'] = pd.to_datetime(df['orderdate'])
# Sort dataframe from last buy to newest (groupby will not change this order)
df2 = df.sort_values(by='orderdate', ascending=False)
# Create an index for joining
df2 = df.set_index('orderdate', drop=False)

# Compute puchases pairs for each customer
df_differences = df2.groupby('customerid').apply(compute_purchase_pairs)
# Show only the ones we care about
result = df_differences[df_differences['timedelta'].dt.days<=5]
result.reset_index(drop=True)
   orderid_first customerid_first orderdate_first  orderid_second  \
0          10318            ISLAT      1996-10-01         10315.0   
1          10321            ISLAT      1996-10-03         10318.0   

  customerid_second orderdate_second timedelta  
0             ISLAT       1996-09-26    5 days  
1             ISLAT       1996-10-01    2 days