按组和虚拟代码分类变量转换长格式分类数据

pivot long form categorical data by group and dummy code categorical variables

对于以下数据框,我试图将分类变量 ('purchase_item') 转换为宽格式并将它们虚拟编码为 1/0 - 基于客户是否在每个2016 年 4 个季度。

我想生成一个旋转数据框,如下所示:

为了获得上面显示的预期结果,我基本上尝试了各种方法来将 groupby/pivot_table 函数与对 pandas 中的 get_dummies() 函数的调用结合起来。例子: data.groupby(["cust_id", "purchase_qtr"])["purchase_item"].reset_index().get_dummies()

但是,到目前为止,我的 none 次尝试都奏效了。

有人可以帮我生成想要的结果吗?

这样做的一种方法是获取交叉制表,然后强制所有 > 1 的值变为 1,同时保持所有 0 的原样:

TL;DR

out = (
    pd.crosstab([df["cust_id"], df["purchase_qtr"]], df["purchase_item"])
    .gt(0)
    .astype(int)
    .reset_index()
)

全部分解:

创建数据

df = pd.DataFrame({
    "group1": np.repeat(["a", "b", "c"], 4),
    "group2": [1, 2, 3] * 4,
    "item": np.random.choice(["ab", "cd", "ef", "gh", "zx"], size=12)
})

print(df)
   group1  group2 item
0       a       1   cd
1       a       2   ef
2       a       3   gh
3       a       1   ef
4       b       2   zx
5       b       3   ab
6       b       1   ab
7       b       2   gh
8       c       3   gh
9       c       1   cd
10      c       2   ef
11      c       3   gh

交叉表

这个 returns 频率 table 表示每个类别一起观察的频率:

crosstab = pd.crosstab([df["group1"], df["group2"]], df["item"])

print(crosstab)
item           ab  cd  ef  gh  zx
group1 group2
a      1        0   1   1   0   0
       2        0   0   1   0   0
       3        0   0   0   1   0
b      1        1   0   0   0   0
       2        0   0   0   1   1
       3        1   0   0   0   0
c      1        0   1   0   0   0
       2        0   0   1   0   0
       3        0   0   0   2   0

将计数强制转换为虚拟代码

由于我们想要伪代码,而不是计算类别的共现,我们可以使用一个快速的技巧来强制所有大于 0 gt(0) 的值变为 1 astype(int)

item           ab  cd  ef  gh  zx
group1 group2
a      1        0   1   1   0   0
       2        0   0   1   0   0
       3        0   0   0   1   0
b      1        1   0   0   0   0
       2        0   0   0   1   1
       3        1   0   0   0   0
c      1        0   1   0   0   0
       2        0   0   1   0   0
       3        0   0   0   1   0

您可以通过多种技巧在一行中完成。

1) 联结中的唯一索引计数与铸造为 bool

在任何情况下都有效,即使除了 indexcolumnsvalues 之外没有任何其他列。此代码意味着计算每个索引列交集的唯一索引,并 returning 1 以防其超过 0 else 0.

df.reset_index().pivot_table(index=['cust_id','purchase_qtr'], 
                             columns='purchase_item',
                             values='index',
                             aggfunc='nunique', fill_value=0)\
                .astype(bool).astype(int)

2) 检查是否有任何其他列不为空

如果您除了 indexcolumnsvalues 之外还有其他列,并且想将它们用于直觉。就像你的 purchase_date 一样。它更直观,因为您可以像这样“阅读”它:如果商品的购买日期不为空,则每季度检查每个客户并将它们解析为整数。

df.pivot_table(index=['cust_id','purchase_qtr'],
               columns='purchase_item',values='purchase_date',
               aggfunc=lambda x: all(pd.notna(x)), fill_value=0)\
  .astype(int)

3) 查看 len 个元素落入每个索引列交集

这会看到 len 个元素落在每个索引列交集中,并且 returning 1 以防超过 0 else 0。同样直观的方法:

df.pivot_table(index=['cust_id','purchase_qtr'], 
               columns='purchase_item',
               values='purchase_date',
               aggfunc=len, fill_value=0)\
  .astype(bool).astype(int)

所有 return 所需的数据帧:

请注意,当您还没有数据框时,您应该只使用 crosstab,因为它会在内部调用 pivot_table