【问题标题】:Python pandas groupby conditional concatenate strings into multiple columnsPython pandas groupby有条件地将字符串连接成多列
【发布时间】:2016-11-10 03:54:03
【问题描述】:

我正在尝试按一列上的数据框进行分组,在每组中保留一行中的几列,并根据一列的值将其他行中的字符串连接成多列。这是一个例子......

df = pd.DataFrame({'test' : ['a','a','a','a','a','a','b','b','b','b'],
     'name' : ['aa','ab','ac','ad','ae','ba','bb','bc','bd','be'],
     'amount' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 9.5],
     'role' : ['x','y','y','x','x','z','y','y','z','y']})

df

      amount    name    role    test
0        1.0    aa      x       a
1        2.0    ab      y       a
2        3.0    ac      y       a
3        4.0    ad      x       a
4        5.0    ae      x       a
5        6.0    ba      z       a
6        7.0    bb      y       b
7        8.0    bc      y       b
8        9.0    bd      z       b
9        9.5    be      y       b

我想在测试中进行分组,当角色 = 'z' 时保留名称和数量,创建一个列(我们称之为 X),当角色 = 'x' 和另一列(我们称之为Y) 当角色 = 'y' 时连接名称的值。 [用'分隔的连接值; '] 每个测试值可能有零到多行角色 = 'x',零到多行角色 = 'y' 和一行角色 = 'z'。对于 X 和 Y,如果该角色没有用于该测试的行,则这些可以为 null。对于角色 = 'x' 或 'y' 的所有行,将删除金额值。所需的输出类似于:

     test   name     amount        X              Y
0    a      ba          6.0        aa; ad; ae     ab; ac
1    b      bd          9.0        None           bb; bc; be

对于连接部分,我找到了x.ix[x.role == 'x', X] = "{%s}" % '; '.join(x['name']),我可以为 y 重复。我尝试了一些类似name = x[x.role == 'z'].name.first() 的名称和金额。我还尝试过定义函数和 lambda 函数的两条路径,但均未成功。欣赏任何想法。

【问题讨论】:

    标签: python pandas group-by conditional string-concatenation


    【解决方案1】:

    您可以在groupby 之后的apply 函数中创建自定义列,如下所示,其中g 可以被视为在测试列中具有单个值的子数据框,并且由于您希望返回多个列,因此您需要为每个组创建一个Series 对象,其中索引是结果中的相应标题:

    df.groupby('test').apply(lambda g: pd.Series({'name': g['name'][g.role == 'z'].iloc[0],
                                                  'amount': g['amount'][g.role == 'z'].iloc[0], 
                                                  'X': '; '.join(g['name'][g.role == 'x']), 
                                                  'Y': '; '.join(g['name'][g.role == 'y'])
                                                 })).reset_index()
    

    【讨论】:

      【解决方案2】:
      # set index and get crossection where test is 'z'
      z = df.set_index(['test', 'role']).xs('z', level='role')
      # get rid of 'z' rows and group by 'test' and 'role' to join names
      xy = df.query('role != "z"').groupby(['test', 'role'])['name'].apply(';'.join).unstack()
      # make columns of xy upper case
      xy.columns = xy.columns.str.upper()
      
      pd.concat([z, xy], axis=1).reset_index()
      

      【讨论】:

        猜你喜欢
        • 2015-11-14
        • 1970-01-01
        • 1970-01-01
        • 2017-05-14
        • 2022-04-06
        • 1970-01-01
        • 2015-01-01
        • 2015-02-02
        相关资源
        最近更新 更多