我试图弄清楚哪些顾客会一起购买服装。我可以找出确切的组合,但是我不知道的问题是包含组合+其他的计数。
例如,我有:
Cust_num Item Rev
Cust1 Shirt1 $40
Cust1 Shirt2 $40
Cust1 Shorts1 $40
Cust2 Shirt1 $40
Cust2 Shorts1 $40
这应该导致:
Combo Count
Shirt1,Shirt2,Shorts1 1
Shirt1,Shorts1 2
我能做的最好的就是独特的组合:
Combo Count
Shirt1,Shirt2,Shorts1 1
Shirt1,Shorts1 1
我尝试过:
df = df.pivot(index='Cust_num',columns='Item').sum()
df[df.notnull()] = "x"
df = df.loc[:,"Shirt1":].replace("x", pd.Series(df.columns, df.columns))
col = df.stack().groupby(level=0).apply(','.join)
df2 = pd.DataFrame(col)
df2.groupby([0]).size().reset_index(name='counts')
但这只是独特的计数。
答案 0 :(得分:8)
使用pandas.DataFrame.groupby
:
grouped_item = df.groupby('Cust_num')['Item']
subsets = grouped_item.apply(lambda x: set(x)).tolist()
Count = [sum(s2.issubset(s1) for s1 in subsets) for s2 in subsets]
combo = grouped_item.apply(lambda x:','.join(x))
combo = combo.reset_index()
combo['Count']=Count
输出:
Cust_num Item Count
0 Cust1 Shirt1,Shirt2,Shorts1 1
1 Cust2 Shirt1,Shorts1 2
答案 1 :(得分:2)
我认为您需要先创建项目组合。
How to get all possible combinations of a list’s elements?
我使用了 Dan H 的答案中的功能。
from itertools import chain, combinations
def all_subsets(ss):
return chain(*map(lambda x: combinations(ss, x), range(0, len(ss)+1)))
uq_items = df.Item.unique()
list(all_subsets(uq_items))
[(),
('Shirt1',),
('Shirt2',),
('Shorts1',),
('Shirt1', 'Shirt2'),
('Shirt1', 'Shorts1'),
('Shirt2', 'Shorts1'),
('Shirt1', 'Shirt2', 'Shorts1')]
并使用groupby
每个客户来获得他们的商品组合。
ls = []
for _, d in df.groupby('Cust_num', group_keys=False):
# Get all possible subset of items
pi = np.array(list(all_subsets(d.Item)))
# Fliter only > 1
ls.append(pi[[len(l) > 1 for l in pi]])
然后转换为Series
并使用value_counts()
。
pd.Series(np.concatenate(ls)).value_counts()
(Shirt1, Shorts1) 2
(Shirt2, Shorts1) 1
(Shirt1, Shirt2, Shorts1) 1
(Shirt1, Shirt2) 1
答案 2 :(得分:2)
最新答案,但您可以使用:
df = df.groupby(['Cust_num'], as_index=False).agg(','.join).drop(columns=['Rev']).set_index(['Item']).rename_axis("combo").rename(columns={"Cust_num": "Count"})
df['Count'] = df['Count'].str.replace(r'Cust','')
combo Count
Shirt1,Shirt2,Shorts1 1
Shirt1,Shorts1 2
答案 3 :(得分:0)
我认为我的版本更容易理解
new_df = df.groupby("Cust_num").agg({lambda x: ''.join(x.unique())})
new_df ['count'] = range(1, len(new_df ) + 1)
输出:
Item Rev count
<lambda> <lambda>
Cust_num
Cust1 Shirt1 Shirt2 Shorts1 $40 1
Cust2 Shirt1 Shorts1 $40 2
由于您不需要Rev
列,因此可以将其删除:
new_df = new_df = new_df.drop(columns=["Rev"]).reset_index()
new_df
输出:
Cust_num Item count
<lambda>
0 Cust1 Shirt1 Shirt2 Shorts1 1
1 Cust2 Shirt1 Shorts1 2
此编辑旨在通过查看他使用列表理解编写的方法来回应@Chris
。他创建了一组列表:
[{' Shirt1', ' Shirt2', ' Shorts1'}, {' Shirt1', ' Shorts1'}]
然后下一步找到子集:
for s1 in subsets:
for s2 in subsets:
if s2.issubset(s1):
print("{}: {}".format(s2,s2.issubset(s1)))
输出:
{' Shirt2', ' Shorts1', ' Shirt1'}: True
{' Shorts1', ' Shirt1'}: True
{' Shorts1', ' Shirt1'}: True
您让我解释自己,我做到了。但是,经过深思熟虑,我意识到您的方法也是错误的。因此,我并不是在嘲笑您,而是感谢您让我考虑解决方案。也感谢@ResidentSleeper的解决方案。