聚合pandas数据帧中的单元格/列

时间:2018-02-23 19:12:18

标签: python pandas dataframe

我有一个像这样的数据框

Index Z1       Z2       Z3       Z4  
 0    A(Z1W1)  A(Z2W1)  A(Z3W1) B(Z4W2)   
 1    A(Z1W3)  B(Z2W1)  A(Z3W2) B(Z4W3)   
 2    B(Z1W1)           A(Z3W4) B(Z4W4)
 3    B(Z1W2)

我想将其转换为

Index   Z1              Z2        Z3                    Z4
 0      A(Z1W1,Z1W3)    A(Z2W1)   A(Z3W1,Z3W2,Z3W4)     B(Z4W2,Z4W3,Z4W4)    
 1      B(Z1W1,Z1W2)    B(Z2W1)     

基本上我想将不同单元格的值聚合到一个单元格,如上所示

修改1

实际列名称是两个单词或3个单词的名称,而不是A B. 例如坚果黄油而不是A

3 个答案:

答案 0 :(得分:3)

事情变得越来越感兴趣: - )

/dev/null

更新 改变

enum error_topic_codes { 
    ET_INPUT, ET_CRUNCHING, ET_FROBNICATING, ET_OUTPUT,
    ET_MISC
};
struct error_report_s {
    const char *label;
    FILE *fp;
};
static struct error_report_s error_destinations[] = {
    /* ET_INPUT */        { "input", 0 },
    /* ET_CRUNCHING */    { "crunching", 0 },
    /* ET_FROBNICATING */ { "frobnicating", 0 },
    /* ET_OUTPUT */       { "output", 0 },
    /* ET_MISC */         { "misc", 0 },
};

void error_report_init (const char *squelched)
{
    FILE *devnull = fopen("/dev/null", "w");
    if (!devnull) {
        perror("/dev/null");
        exit(1);
    }
    for (int i = 0; i <= ET_MISC; i++)
        error_destinations[i].fp =
            strstr(squelched, error_destinations[i].label)
            ? devnull : stderr;
    /* FIXME 2018-02-23: This leaks a FILE if none of the
       error categories are squelched.  */
}

s=df.stack().replace({'[(|)]':' '},regex=True).str.strip().str.split(' ',expand=True)
v=('('+s.groupby([s.index.get_level_values(1),s[0]])[1].apply(','.join)+')').unstack().apply(lambda x : x.name+x.astype(str)).T
v[~v.apply(lambda x : x.str.contains('None'))].apply(lambda x : sorted(x,key=pd.isnull)).reset_index(drop=True)
Out[1865]: 
             Z1       Z2                 Z3                 Z4
0  A(Z1W1,Z1W3)  A(Z2W1)  A(Z3W1,Z3W2,Z3W4)  B(Z4W2,Z4W3,Z4W4)
1  B(Z1W1,Z1W2)  B(Z2W1)                NaN                NaN

答案 1 :(得分:2)

基因思想:

  1. 拆分字符串值
  2. 重新组合并加入刺痛
  3. 适用于所有列
  4. 更新1

    # I had to add parameter as_index=False to groupby(0) 
    # to get exactly same output as asked
    

    让我们尝试一栏

    def str_regroup(s):
    return s.str.extract(r"(\w)\((.+)\)",expand=True).groupby(0,as_index=False).apply(
        lambda x: '{}({})'.format(x.name,', '.join(x[1])))
    str_regroup(df1.Z1)
    

    输出

    A   A(Z1W1, Z1W3)
    B   B(Z1W1, Z1W2)
    

    然后适用于所有列

    df.apply(str_regroup)
    

    输出

        Z1  Z2  Z3  Z4
    0   A(Z1W1, Z1W3)   A(Z2W1) A(Z3W1, Z3W2, Z3W4) B(Z4W2, Z4W3, Z4W4)
    1   B(Z1W1, Z1W2)   B(Z2W1)     
    

    更新2
    10 000个样本行性能

      此<{1}}版本的
    • 928 ms ; b
    • @Len 为apply
    • 1.55 s

答案 2 :(得分:1)

您可以使用以下方法:

    得到:
  • Melt df

    In [194]: melted = pd.melt(df, var_name='col'); melted
    Out[194]: 
       col    value
    0   Z1  A(Z1W1)
    1   Z1  A(Z1W3)
    2   Z1  B(Z1W1)
    3   Z1  B(Z1W2)
    4   Z2  A(Z2W1)
    5   Z2  B(Z2W1)
    6   Z2         
    7   Z2         
    8   Z3  A(Z3W1)
    9   Z3  A(Z3W2)
    10  Z3  A(Z3W4)
    11  Z3         
    12  Z4  B(Z4W2)
    13  Z4  B(Z4W3)
    14  Z4  B(Z4W4)
    15  Z4         
    
  • 使用正则表达式提取rowvalue列:

    In [195]: melted[['row','value']] = melted['value'].str.extract(r'(.*)\((.*)\)', expand=True); melted
    Out[195]: 
       col value  row
    0   Z1  Z1W1    A
    1   Z1  Z1W3    A
    2   Z1  Z1W1    B
    3   Z1  Z1W2    B
    4   Z2  Z2W1    A
    5   Z2  Z2W1    B
    6   Z2   NaN  NaN
    7   Z2   NaN  NaN
    8   Z3  Z3W1    A
    9   Z3  Z3W2    A
    10  Z3  Z3W4    A
    11  Z3   NaN  NaN
    12  Z4  Z4W2    B
    13  Z4  Z4W3    B
    14  Z4  Z4W4    B
    15  Z4   NaN  NaN
    
  • colrow分组并加入value

    In [185]: result = melted.groupby(['col', 'row'])['value'].agg(','.join)
    In [186]: result
    Out[186]: 
    col  row
    Z1   A           Z1W1,Z1W3
         B           Z1W1,Z1W2
    Z2   A                Z2W1
         B                Z2W1
    Z3   A      Z3W1,Z3W2,Z3W4
    Z4   B      Z4W2,Z4W3,Z4W4
    Name: value, dtype: object
    
  • row值添加到value值:

    In [188]: result['value'] = result['row'] + '(' + result['value'] + ')'
    In [189]: result
    Out[189]: 
        row              value
    col                       
    Z1    A       A(Z1W1,Z1W3)
    Z1    B       B(Z1W1,Z1W2)
    Z2    A            A(Z2W1)
    Z2    B            B(Z2W1)
    Z3    A  A(Z3W1,Z3W2,Z3W4)
    Z4    B  B(Z4W2,Z4W3,Z4W4)
    
  • 使用row值覆盖groupby/cumcount列值以设置即将到来的支点:

    In [191]: result['row'] = result.groupby(level='col').cumcount()
    In [192]: result
    Out[192]: 
         row              value
    col                        
    Z1     0       A(Z1W1,Z1W3)
    Z1     1       B(Z1W1,Z1W2)
    Z2     0            A(Z2W1)
    Z2     1            B(Z2W1)
    Z3     0  A(Z3W1,Z3W2,Z3W4)
    Z4     0  B(Z4W2,Z4W3,Z4W4)
    
  • 透视产生所需的结果:

    result = result.pivot(index='row', columns='col', values='value')
    
import pandas as pd
df = pd.DataFrame({
 'Z1': ['A(Z1W1)', 'A(Z1W3)', 'B(Z1W1)', 'B(Z1W2)'],
 'Z2': ['A(Z2W1)', 'B(Z2W1)', '', ''],
 'Z3': ['A(Z3W1)', 'A(Z3W2)', 'A(Z3W4)', ''],
 'Z4': ['B(Z4W2)', 'B(Z4W3)', 'B(Z4W4)', '']}, index=[0, 1, 2, 3],)

melted = pd.melt(df, var_name='col').dropna()
melted[['row','value']] = melted['value'].str.extract(r'(.*)\((.*)\)', expand=True)
result = melted.groupby(['col', 'row'])['value'].agg(','.join)
result = result.reset_index('row')
result['value'] = result['row'] + '(' + result['value'] + ')'
result['row'] = result.groupby(level='col').cumcount()
result = result.reset_index()
result = result.pivot(index='row', columns='col', values='value')
print(result)

产量

col            Z1       Z2                 Z3                 Z4
row                                                             
0    A(Z1W1,Z1W3)  A(Z2W1)  A(Z3W1,Z3W2,Z3W4)  B(Z4W2,Z4W3,Z4W4)
1    B(Z1W1,Z1W2)  B(Z2W1)                NaN                NaN