Python pandas如何分组匹配
Python pandas how to group and match
假设我们有两个 table,trans
和 product
。假设 trans
table 包含用户购买的超过十亿行。
我正在尝试查找同一用户经常一起购买(同一天购买)的配对产品,例如葡萄酒和开瓶器、薯条和啤酒等。
我正在尝试查找前五个配对产品及其名称。
trans 和 prod 数据帧:-
trans = {'ID':[1,1,2,2,3,3,1,5,5,6,6,6],
'productID':[11,22,11,22,33,77,11,77,88,11,22,77],
'Year':['2022-01-01','2022-01-01','2020-01-05','2020-01-05','2019-01-01','2019-01-01','2020-01-07','2020-01-08',
'2020-01-08','2021-06-01','2021-06-01','2021-06-01']}
trans = pd.DataFrame(trans)
trans['Year'] = pd.to_datetime(trans['Year'])
trans
product = {'productID':[11,22,33,44,55,77,88],
'prodname':['phone','Charger','eaphones','headset','scratchgaurd','pin','cover']}
product = pd.DataFrame(product)
product
到目前为止,我的代码尝试对具有相同 ID 和年份的项目进行排名,然后尝试获取产品名称。
transprod = pd.merge(trans,product,on='productID' , how='inner')
transprod
transprod['Rank'] = transprod.groupby('ID')['Year'].rank(method = 'dense').astype(int)
transprod = transprod.sort_values(['ID','productID','Rank'])
transprod
期望的输出:
Product 1 | Product 2 | Count
phone charger 3
Charger pin 1
eaphones pin 1
pin cover 1
非常感谢您的帮助。提前致谢
您可以按 ID(和日期)对交易 table 进行分组,并列出每个订单的所有产品对。 itertools.combinations
在这里很有用。通过先把集合放在一个订单上,你可以忽略多个相同的项目。
由于一对出现的顺序无关紧要,因此您可以构建所有对的平面列表并使用 collections.Counter
实例对它们进行计数。首先对每对进行排序确保您可以忽略一对中项目的顺序。
产品table可以转化为字典,方便查找。这将提供一种将产品名称添加到 table 结果的方法。
from itertools import combinations
from collections import Counter
pairs_by_trans = trans.groupby(['ID', 'Year'])['productID'].agg(
lambda x: list(combinations(set(x), 2)))
pairs_flat = [tuple(sorted(pair)) for row in pairs_by_trans for pair in row]
counts = Counter(pairs_flat)
top_counts = pd.DataFrame(counts.most_common(5),
columns=['pair', 'count'])
prodname = {k: v for k, v in product.values}
top_counts['names'] = top_counts['pair'].apply(lambda x: (prodname[x[0]],
prodname[x[1]]))
top_counts
pair count names
0 (11, 22) 3 (phone, Charger)
1 (33, 77) 1 (eaphones, pin)
2 (77, 88) 1 (pin, cover)
3 (11, 77) 1 (phone, pin)
4 (22, 77) 1 (Charger, pin)
下面的解决方案非常适合我
transprod = pd.merge(trans,product,on='productID' , how='inner')
transprod['Rank'] = transprod.groupby('ID')['Year'].rank(method = 'dense').astype(int)
transprod = transprod.sort_values(['ID','productID','Rank'])
def checkprod(x):
v1 = (x['Rank']==x['Rank'].shift(-1))
return (x[v1 | v1.shift(1)])
out = transprod.groupby('ID').apply(checkprod).reset_index(drop=True)
pairs = out.groupby(['ID','Rank'])['prodname'].agg(
lambda x: list(combinations(set(x), 2)))
Counter(list(itertools.chain(*pairs)))
假设我们有两个 table,trans
和 product
。假设 trans
table 包含用户购买的超过十亿行。
我正在尝试查找同一用户经常一起购买(同一天购买)的配对产品,例如葡萄酒和开瓶器、薯条和啤酒等。
我正在尝试查找前五个配对产品及其名称。
trans 和 prod 数据帧:-
trans = {'ID':[1,1,2,2,3,3,1,5,5,6,6,6],
'productID':[11,22,11,22,33,77,11,77,88,11,22,77],
'Year':['2022-01-01','2022-01-01','2020-01-05','2020-01-05','2019-01-01','2019-01-01','2020-01-07','2020-01-08',
'2020-01-08','2021-06-01','2021-06-01','2021-06-01']}
trans = pd.DataFrame(trans)
trans['Year'] = pd.to_datetime(trans['Year'])
trans
product = {'productID':[11,22,33,44,55,77,88],
'prodname':['phone','Charger','eaphones','headset','scratchgaurd','pin','cover']}
product = pd.DataFrame(product)
product
到目前为止,我的代码尝试对具有相同 ID 和年份的项目进行排名,然后尝试获取产品名称。
transprod = pd.merge(trans,product,on='productID' , how='inner')
transprod
transprod['Rank'] = transprod.groupby('ID')['Year'].rank(method = 'dense').astype(int)
transprod = transprod.sort_values(['ID','productID','Rank'])
transprod
期望的输出:
Product 1 | Product 2 | Count
phone charger 3
Charger pin 1
eaphones pin 1
pin cover 1
非常感谢您的帮助。提前致谢
您可以按 ID(和日期)对交易 table 进行分组,并列出每个订单的所有产品对。 itertools.combinations
在这里很有用。通过先把集合放在一个订单上,你可以忽略多个相同的项目。
由于一对出现的顺序无关紧要,因此您可以构建所有对的平面列表并使用 collections.Counter
实例对它们进行计数。首先对每对进行排序确保您可以忽略一对中项目的顺序。
产品table可以转化为字典,方便查找。这将提供一种将产品名称添加到 table 结果的方法。
from itertools import combinations
from collections import Counter
pairs_by_trans = trans.groupby(['ID', 'Year'])['productID'].agg(
lambda x: list(combinations(set(x), 2)))
pairs_flat = [tuple(sorted(pair)) for row in pairs_by_trans for pair in row]
counts = Counter(pairs_flat)
top_counts = pd.DataFrame(counts.most_common(5),
columns=['pair', 'count'])
prodname = {k: v for k, v in product.values}
top_counts['names'] = top_counts['pair'].apply(lambda x: (prodname[x[0]],
prodname[x[1]]))
top_counts
pair count names
0 (11, 22) 3 (phone, Charger)
1 (33, 77) 1 (eaphones, pin)
2 (77, 88) 1 (pin, cover)
3 (11, 77) 1 (phone, pin)
4 (22, 77) 1 (Charger, pin)
下面的解决方案非常适合我
transprod = pd.merge(trans,product,on='productID' , how='inner')
transprod['Rank'] = transprod.groupby('ID')['Year'].rank(method = 'dense').astype(int)
transprod = transprod.sort_values(['ID','productID','Rank'])
def checkprod(x):
v1 = (x['Rank']==x['Rank'].shift(-1))
return (x[v1 | v1.shift(1)])
out = transprod.groupby('ID').apply(checkprod).reset_index(drop=True)
pairs = out.groupby(['ID','Rank'])['prodname'].agg(
lambda x: list(combinations(set(x), 2)))
Counter(list(itertools.chain(*pairs)))