【问题标题】:pivot long form categorical data by group and dummy code categorical variables按组和虚拟代码分类变量透视长格式分类数据
【发布时间】:2021-12-19 03:00:48
【问题描述】:

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

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

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

但是,到目前为止,我的任何尝试都没有奏效。

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

【问题讨论】:

    标签: python pandas-groupby pivot-table one-hot-encoding dummy-variable


    【解决方案1】:

    这样做的一种方法是获取交叉表,然后强制所有大于 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
    

    交叉列表

    这会返回一个频率表,指示每个类别被一起观察的频率:

    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
    

    【讨论】:

    • 虽然这适用于此处的示例,但对于非常大的数据集,它似乎导致 cust_id 的数量少于长格式数据帧的预期数量。知道如何防止这种情况吗?我从下面列出的其他替代方案中也遇到了同样的问题
    【解决方案2】:

    你可以通过几个技巧在一行中完成。

    1) 与转换为 bool 结合的唯一索引计数

    即使您没有除indexcolumnsvalues 之外的任何其他列,也可以在任何情况下工作。此代码意味着计算每个索引列交集的唯一索引并返回 1 以防其超过 0 否则 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 的元素落在每个索引列交集并返回1 以防它超过0 否则0。同样直观的方法:

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

    全部返回所需的数据帧:

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

    【讨论】:

    • 虽然这适用于此处的示例,但对于非常大的数据集,它似乎导致 cust_id 的数量少于长格式数据帧的预期数量。知道如何防止这种情况吗?我也从上面列出的其他替代方案中遇到了同样的问题。
    猜你喜欢
    • 2018-09-01
    • 1970-01-01
    • 2016-03-19
    • 2014-10-14
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    相关资源
    最近更新 更多