【问题标题】:Convert column values to column of list based on condition根据条件将列值转换为列表列
【发布时间】:2019-06-25 12:33:54
【问题描述】:

数据集为:

   id  col2  col3
0   1     1   123
1   1     1   234
2   1     0   345
3   2     1   456
4   2     0  1243
5   2     0   346
6   3     0   888
7   3     0   999
8   3     0   777

我想通过 id 聚合数据,并且仅当 col2 的对应值是 1 时才将 col3 的值附加到列表中。此外,对于仅col2 中有 0,我希望 col2 的聚合值为 0,col3 的聚合值为空。

这是当前代码:

df_test = pd.DataFrame({'id':[1, 1, 1, 2, 2, 2, 3, 3, 3], 'col2':[1, 1, 0, 1, 0, 0, 0, 0, 0], 'col3':[123, 234, 345, 456, 1243, 346, 888, 999, 777]})

df_test_agg = pd.pivot_table(df_test, index=['id'], values=['col2', 'col3'], aggfunc={'col2':np.max, 'col3':(lambda x:list(x))})

print (df_test_agg)

    col2              col3
id                        
1      1   [123, 234, 345]
2      1  [456, 1243, 346]
3      0   [888, 999, 777]

所需的输出应该是(最好是在 Pandas 中一步完成):

    col2              col3
id                        
1      1            [123, 234]
2      1            [456]
3      0            []

/////////////////////////////////////// ////////////////////////////////////////////p>

编辑 - 试用 ColdSpeed 的解决方案

df_test = pd.DataFrame({'id':[1, 1, 1, 2, 2, 2, 3, 3, 3], 'col2':[1, 1, 0, 1, 0, 0, 0, 0, 0], 'col3':[123, 234, 345, 456, 1243, 346, 888, 999, 777]})

print (df_test)

df_test_agg = (df_test.where(df_test.col2 > 0)
    .assign(id=df_test.id)
    .groupby('id')
    .agg({'col2': 'max', 'col3': lambda x: x.dropna().tolist()}))

print (df_test_agg)

   id  col2  col3
0   1     1   123
1   1     1   234
2   1     0   345
3   2     1   456
4   2     0  1243
5   2     0   346
6   3     0   888
7   3     0   999
8   3     0   777
    col2            col3
id                      
1    1.0  [123.0, 234.0]
2    1.0         [456.0]
3    NaN              []

/////////////////////////////////////// ////////////////////////////////////////////p>

编辑原始帖子以呈现更多场景。

【问题讨论】:

    标签: python python-3.x pandas group-by pandas-groupby


    【解决方案1】:

    你可以预先过滤,然后使用groupby:

    df_test.query('col2 > 0').groupby('id').agg({'col2': 'max', 'col3': list})
    
        col2        col3
    id                  
    1      1  [123, 234]
    2      1       [456]
    

    这里需要注意的是,如果一个组只有零,那么该组将在结果中丢失。因此,要解决此问题,您可以使用 where 进行屏蔽:

    (df_test.where(df_test.col2 > 0)
            .assign(id=df_test.id)
            .groupby('id')
            .agg({'col2': 'max', 'col3'lambda x: x.dropna().tolist()}))
    
        col2            col3
    id                      
    1    1.0  [123.0, 234.0]
    2    1.0         [456.0]
    

    要处理 "col2" 中的 0 个组,我们可以使用

    (df.assign(col3=df.col3.where(df.col2.astype(bool)))
       .groupby('id')
       .agg({'col2':'max', 'col3': lambda x: x.dropna().astype(int).tolist()}))
    
        col2        col3
    id                  
    1      1  [123, 234]
    2      1       [456]
    3      0          []
    

    【讨论】:

    • 我确实想保留 col2=0 组。这就是为什么我更喜欢一步解决方案而不是先过滤掉一些子组。
    • @KubiK888 没有一步到位的解决方案,因为agg 在这种状态下只能访问单个系列,而不是多个列。第二个建议有什么问题吗?
    • 将在计算机上测试您的第二个解决方案。谢谢。
    • @KubiK888 这是一种在不修改原始DataFrame的情况下分配新列(或重新分配现有列)的方法。表达式 df.col3.where(df.col2.astype(bool)) 会将所有 col3 值转换为 NaN,其中 col2 为 0。
    • @KubiK888 是的。原df 未修改。 assign 创建 DataFrame 的副本,并在返回之前为该副本分配一个新列。如果您更喜欢就地分配,那也可以,但这是两个步骤 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-30
    • 2016-03-01
    • 2022-11-10
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    相关资源
    最近更新 更多