python - 如何创建在python中订购的产品的共现矩阵?

标签 python pandas product

假设我们有以下数据框,其中包括客户订单 (order_id) 和单个订单包含的产品 (product_id):

import pandas as pd

df = pd.DataFrame({'order_id' : [1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3],
                   'product_id' : [365, 48750, 3333, 9877, 48750, 32001, 3333, 3333, 365, 11202, 365]})
print(df)

   order_id product_id
0         1        365
1         1      48750
2         1       3333
3         1       9877
4         2      48750
5         2      32001
6         2       3333
7         3       3333
8         3        365
9         3      11202
10        3        365
了解产品对一起出现在同一个篮子中的频率会很有趣。
如何在 python 中创建一个共现矩阵,如下所示:
       365  48750  3333  9877  32001  11202
365      1      1     2     1      0      1
48750    1      0     2     1      1      0
3333     2      2     0     1      1      1
9877     1      1     1     0      0      0
32001    0      1     1     0      0      0
11202    1      0     1     0      0      0
我将非常感谢您的帮助!

最佳答案

我们首先按 order_id 对 df 进行分组,然后在每个组内计算所有可能的对。请注意,我们首先按 product_id 排序,因此不同组中的相同对始终处于相同的顺序

import itertools
all_pairs = []
for _, group in df.sort_values('product_id').groupby('order_id'):
    all_pairs += list(itertools.combinations(group['product_id'],2))

all_pairs
我们从所有订单中获得所有对的列表
[('3333', '365'),
 ('3333', '48750'),
 ('3333', '9877'),
 ('365', '48750'),
 ('365', '9877'),
 ('48750', '9877'),
 ('32001', '3333'),
 ('32001', '48750'),
 ('3333', '48750'),
 ('11202', '3333'),
 ('11202', '365'),
 ('11202', '365'),
 ('3333', '365'),
 ('3333', '365'),
 ('365', '365')]
现在我们计算重复
from collections import Counter

count_dict = dict(Counter(all_pairs))
count_dict
所以我们得到每对的数量,基本上是你所追求的
{('3333', '365'): 3,
 ('3333', '48750'): 2,
 ('3333', '9877'): 1,
 ('365', '48750'): 1,
 ('365', '9877'): 1,
 ('48750', '9877'): 1,
 ('32001', '3333'): 1,
 ('32001', '48750'): 1,
 ('11202', '3333'): 1,
 ('11202', '365'): 2,
 ('365', '365'): 1}
将其放回交叉产品表需要一些工作,关键位是通过调用 .apply(pd.Series) 将元组拆分为列。并最终通过 unstack 将其中一列移至列名:
(pd.DataFrame.from_dict(count_dict, orient='index')
    .reset_index(0)
    .set_index(0)['index']
    .apply(pd.Series)
    .rename(columns = {0:'pid1',1:'pid2'})
    .reset_index()
    .rename(columns = {0:'count'})
    .set_index(['pid1', 'pid2'] )
    .unstack()
    .fillna(0))
这会产生您所追求的表格的“紧凑”形式,仅包括至少出现在一对中的产品

count
pid2    3333 365    48750  9877
pid1                
11202   1.0  2.0    0.0    0.0
32001   1.0  0.0    1.0    0.0
3333    0.0  3.0    2.0    1.0
365     0.0  1.0    1.0    1.0
48750   0.0  0.0    0.0    1.0
更新
这是上述内容的一个相当简化的版本,在评论中进行了各种讨论
import numpy as np
import pandas as pd
from collections import Counter

# we start as in the original solution but use permutations not combinations
all_pairs = []
for _, group in df.sort_values('product_id').groupby('order_id'):
    all_pairs += list(itertools.permutations(group['product_id'],2))
count_dict = dict(Counter(all_pairs))

# We create permutations for _all_ product_ids ... note we use unique() but also product(..) to allow for (365,265) combinations
total_pairs = list(itertools.product(df['product_id'].unique(),repeat = 2))

# pull out first and second elements separately
pid1 = [p[0] for p in total_pairs]
pid2 = [p[1] for p in total_pairs]

# and get the count for those permutations that exist from count_dict. Use 0
# for those that do not
count = [count_dict.get(p,0) for p in total_pairs]

# Now a bit of dataFrame magic
df_cross = pd.DataFrame({'pid1':pid1, 'pid2':pid2, 'count':count})
df_cross.set_index(['pid1','pid2']).unstack()
我们已经完成了。 df_cross以下

count
pid2    11202   32001   3333    365 48750   9877
pid1                        
11202   0       0       1       2   0       0
32001   0       0       1       0   1       0
3333    1       1       0       3   2       1
365     2       0       3       2   1       1
48750   0       1       2       1   0       1
9877    0       0       1       1   1       0

关于python - 如何创建在python中订购的产品的共现矩阵?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64837148/

相关文章:

python - Pandas ,在 groupby 之后创建列

python - Pandas dp 删除具有多个字符串的行

php - WooCommerce 存档页面产品查询上的多个 orderby 参数

php - 仅获取 WooCommerce 产品的一个产品类别术语

python - 在 Python 中倾斜数组

python - 查找txt文件中的行号或元素

python - 如何将欧几里德距离函数应用于 Pandas 数据框中的 groupby 对象?

php - 如果产品在 Woocommerce 中不征税,则隐藏额外的不含税价格

python - Scrapy 请求回调未触发

python - Cython 编译将文本附加到文件名,如何摆脱它?