使用熊猫交叉表来计算类别列上的交叉计数

时间:2018-09-18 08:15:17

标签: python pandas crosstab

我有一张带有客户购买产品类别的表。 我正在尝试建立一个交叉销售矩阵,计算出每对产品类别中的唯一客户,并同时得出一个具有唯一计数的总数。

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有助于在交叉表中用正确的数字填充单元格,但会导致小计/边距计算错误

我期望的是:

| 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

我已经尝试了一些计数,独特性...到目前为止还没有成功。

编辑

jezrael的答案很好,但是我想知道他们是否是使用正确的crosstab通过aggfunc直接完成此操作的一种方法。

2 个答案:

答案 0 :(得分:1)

您可以按groupby.nunique计数值,并按joinappend手动添加值:

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

答案 1 :(得分:0)

我认为这满足了我的需求

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(此处为dd.cust)的唯一值的长度/大小。