我已经尝试解决一个问题了好几个小时,并且一直坚持下去。问题概述如下:
import numpy as np
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']})
df
orderid customerid orderdate
0 10315 ISLAT 1996-09-26
1 10318 ISLAT 1996-10-01
2 10321 ISLAT 1996-10-03
3 10473 ISLAT 1997-03-13
4 10621 ISLAT 1997-08-05
5 10253 HANAR 1996-07-10
6 10541 HANAR 1997-05-19
7 10645 HANAR 1997-08-26
我想选择在5天内多次订购商品的所有客户。
例如,在这里,只有客户在5天之内订购了商品,而他又做了两次。
我想以以下格式获取输出:
customerid initial_order_id initial_order_date nextorderid nextorderdate daysbetween
ISLAT 10315 1996-09-26 10318 1996-10-01 5
ISLAT 10318 1996-10-01 10321 1996-10-03 2
答案 0 :(得分:3)
首先,要计算天数差异,请转换 orderdate 列到 datetime :
df.orderdate = pd.to_datetime(df.orderdate)
然后定义以下功能:
def fn(grp):
return grp[(grp.orderdate.shift(-1) - grp.orderdate) / np.timedelta64(1, 'D') <= 5]
最后应用它:
df.sort_values(['customerid', 'orderdate']).groupby('customerid').apply(fn)
答案 1 :(得分:2)
您可以使用sort_values
和diff
创建“ daysweenween”列。获得以下顺序后,您可以每个客户ID join
用df groupby
和df一次,并用shift
的所有数据。最后,query
满足“ daysbetween_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')
答案 2 :(得分:2)
这有点棘手,因为5天之内可以有任意数量的购买对。利用merge_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)
结果
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
答案 3 :(得分:1)
这很简单。让我们一次写下一个需求,然后尝试建立。
首先,我猜该客户具有唯一的ID,因为未指定该ID。我们将使用该ID来识别客户。
第二,我认为客户在购买前后5天购买都没关系。
我的解决方案是使用一个简单的过滤器。请注意,该解决方案也可以在SQL数据库中实现。
作为条件,我们要求用户相同。我们可以实现以下目标:
new_df = df[df["ID"] == df["ID"].shift(1)]
我们创建一个具有所有行的新DataFrame,即new_df,以使第x行与第x-1行(即前一行)具有相同的用户ID。
现在,通过将条件添加到上一段代码中,让我们在5天内搜索购买内容
new_df = df[df["ID"] == df["ID"].shift(1) & (df["Date"] - df["Date"].shift(1)) <= 5]
这应该可以完成工作。我现在无法测试它的编写,因此可能需要一些修复。我会尽快对其进行测试