使用 pandas 交叉表计算类别列的交叉计数
Using pandas crosstab to compute cross count on a category column
我有一个 table 客户购买产品类别。
我正在尝试建立一个交叉销售矩阵,计算每对产品类别的唯一客户,并且总计也有唯一计数。
pandas.crosstab
是一个很好的开始方式,但在小计上失败(即 margins=True
)
df = pd.DataFrame({
'cust': ['1', '1', '2', '3', '3', '4', '5'], # customer ID
'categ': ['a', 'b', 'a', 'a', 'b', 'b', 'b'] # category ID
})
# have 2 columns to make the crosstab
dd = pd.merge(df, df, on='cust')
然后 pd.crosstab(dd.categ_x, dd.categ_y, margins=True)
给出:
| categ_x | a | b | All |
|---------|---|---|-----|
| a | 3 | 2 | 5 |
| b | 2 | 4 | 6 |
| All | 5 | 6 | 11 |
pd.merge
有助于用十字中的正确数字填充单元格table,但会导致 subtotals/margins
的错误计数
我期望的是:
| categ_x | a | b | All |
|---------|---|---|-----|
| a | 3 | 2 | 3 | -- I have 3 unique clients with 'a'
| b | 2 | 4 | 4 | -- I have 4 unique clients with 'b'
| All | 3 | 4 | 5 | -- I have 5 unique clients in total
我已经尝试了一些 count,uniques...到目前为止没有太大的成功。
编辑
jezrael 答案很好,但我想知道他们是否可以使用正确的 aggfunc
.
直接通过 crosstab
来完成
您可以通过 groupby.nunique
and add values manually by join
and append
:
计算值
s = df2.groupby(['categ'])['cust'].nunique().rename('All')
s1 = s.append(pd.Series({'All': df2['cust'].nunique()}, name='All'))
df = pd.crosstab(dd.categ_x, dd.categ_y).join(s).append(s1)
print (df)
a b All
categ_x
a 3 2 3
b 2 4 4
All 3 4 5
另一个类似的解决方案:
s = df2.groupby(['categ'])['cust'].nunique().rename('All')
df = pd.crosstab(dd.categ_x, dd.categ_y).join(s).append(s)
df.loc['All','All'] = df2['cust'].nunique()
df = df.astype(int)
print (df)
a b All
categ_x
a 3 2 3
b 2 4 4
All 3 4 5
我认为这符合我的需要:
pd.crosstab(
dd.categ_x, dd.categ_y, margins=True,
values=dd.cust, aggfunc=pd.Series.nunique
)
给出:
| categ_x | a | b | All |
|---------|---|---|-----|
| a | 3 | 2 | 3 |
| b | 2 | 4 | 4 |
| All | 3 | 4 | 5 |
pd.Series.nunique
给出 values
的唯一值的 length/size(这里是 dd.cust
)。
我有一个 table 客户购买产品类别。 我正在尝试建立一个交叉销售矩阵,计算每对产品类别的唯一客户,并且总计也有唯一计数。
pandas.crosstab
是一个很好的开始方式,但在小计上失败(即 margins=True
)
df = pd.DataFrame({
'cust': ['1', '1', '2', '3', '3', '4', '5'], # customer ID
'categ': ['a', 'b', 'a', 'a', 'b', 'b', 'b'] # category ID
})
# have 2 columns to make the crosstab
dd = pd.merge(df, df, on='cust')
然后 pd.crosstab(dd.categ_x, dd.categ_y, margins=True)
给出:
| categ_x | a | b | All |
|---------|---|---|-----|
| a | 3 | 2 | 5 |
| b | 2 | 4 | 6 |
| All | 5 | 6 | 11 |
pd.merge
有助于用十字中的正确数字填充单元格table,但会导致 subtotals/margins
我期望的是:
| categ_x | a | b | All |
|---------|---|---|-----|
| a | 3 | 2 | 3 | -- I have 3 unique clients with 'a'
| b | 2 | 4 | 4 | -- I have 4 unique clients with 'b'
| All | 3 | 4 | 5 | -- I have 5 unique clients in total
我已经尝试了一些 count,uniques...到目前为止没有太大的成功。
编辑
jezrael 答案很好,但我想知道他们是否可以使用正确的 aggfunc
.
crosstab
来完成
您可以通过 groupby.nunique
and add values manually by join
and append
:
s = df2.groupby(['categ'])['cust'].nunique().rename('All')
s1 = s.append(pd.Series({'All': df2['cust'].nunique()}, name='All'))
df = pd.crosstab(dd.categ_x, dd.categ_y).join(s).append(s1)
print (df)
a b All
categ_x
a 3 2 3
b 2 4 4
All 3 4 5
另一个类似的解决方案:
s = df2.groupby(['categ'])['cust'].nunique().rename('All')
df = pd.crosstab(dd.categ_x, dd.categ_y).join(s).append(s)
df.loc['All','All'] = df2['cust'].nunique()
df = df.astype(int)
print (df)
a b All
categ_x
a 3 2 3
b 2 4 4
All 3 4 5
我认为这符合我的需要:
pd.crosstab(
dd.categ_x, dd.categ_y, margins=True,
values=dd.cust, aggfunc=pd.Series.nunique
)
给出:
| categ_x | a | b | All |
|---------|---|---|-----|
| a | 3 | 2 | 3 |
| b | 2 | 4 | 4 |
| All | 3 | 4 | 5 |
pd.Series.nunique
给出 values
的唯一值的 length/size(这里是 dd.cust
)。