在 pandas 中取消嵌套列时保留空列表

问题描述 投票:0回答:3

背景

我有以下数据框

import pandas as pd
df = pd.DataFrame({'Result' : [['pos', '+', 'pos', 'positive'], ['neg', 'neg'], [], ['pos']], 
                  'P_ID': [1,2,3,4], 
                  'Gene' : [['kras', 'kras', 'kras', 'egfr'], ['brca', 'brca'], [], ['cd133']],
                  'N_ID' : ['A1', 'A2', 'A3', 'A4']

                 })

#rearrange columns
df = df[['P_ID', 'N_ID', 'Gene', 'Result']]
df


  P_ID N_ID         Gene                         Result
0   1   A1  [kras, kras, kras, egfr]    [pos, +, pos, positive]
1   2   A2  [brca, brca]                [neg, neg]
2   3   A3  []                          []
3   4   A4  [cd133]                     [pos]

我使用以下代码取自 unnest (explode) multiple list 2.0

df.set_index('P_ID').apply(lambda x: x.apply(pd.Series).stack()).ffill().reset_index().drop('level_1', 1)

问题

使用上面的代码,我已经接近我想要的了。 但是,因为第三行

Gene
中的
Result
2
列是空列表
[]
,所以我得到其上方行的输出,如下所示:

 P_ID   N_ID Gene   Result
0   1   A1  kras    pos
1   1   A1  kras    +
2   1   A1  kras    pos
3   1   A1  egfr    positive
4   2   A2  brca    neg
5   2   A2  brca    neg
6   3   A3  brca    neg
7   4   A4  cd133   pos

相反,我想得到下面的输出,其中以下行

6   3   A3  []      []
反映了原始数据框
df
,其中包含空列表

所需输出

   P_ID N_ID Gene   Result
0   1   A1  kras    pos
1   1   A1  kras    +
2   1   A1  kras    pos
3   1   A1  egfr    positive
4   2   A2  brca    neg
5   2   A2  brca    neg
6   3   A3  []      []
7   4   A4  cd133   pos

问题

如何获得所需的输出?

python pandas dataframe
3个回答
2
投票

让我们尝试一些堆叠和拆垛魔法。这也保留了空列表。

(df.set_index(['P_ID', 'N_ID'])
   .stack()
   .str.join(',')
   .str.split(',', expand=True)
   .stack()
   .unstack(-2)
   .reset_index(level=[0, 1])
   .reset_index(drop=True))

   P_ID N_ID    Result   Gene
0  1     A1   pos       kras 
1  1     A1   +         kras 
2  1     A1   pos       kras 
3  1     A1   positive  egfr 
4  2     A2   neg       brca 
5  2     A2   neg       brca 
6  3     A3                  
7  4     A4   pos       cd133

详情

首先将不被触及的列设置为索引。

df.set_index(['P_ID', 'N_ID'])

                            Result                      Gene
P_ID N_ID                                                   
1    A1    [pos, +, pos, positive]  [kras, kras, kras, egfr]
2    A2    [neg, neg]               [brca, brca]            
3    A3    []                       []                      
4    A4    [pos]                    [cd133]                 

接下来,

stack
行。

_.stack()

P_ID  N_ID        
1     A1    Result    [pos, +, pos, positive] 
            Gene      [kras, kras, kras, egfr]
2     A2    Result    [neg, neg]              
            Gene      [brca, brca]            
3     A3    Result    []                      
            Gene      []                      
4     A4    Result    [pos]                   
            Gene      [cd133]                 
dtype: object

我们现在有一个系列。我们需要将这些元素分解为单独的列。因此,首先加入列表,然后再次拆分。 假设您的列表元素本身不包含逗号,则此方法有效(如果不包含,请找到另一个分隔符来连接和拆分)。

_.str.join(',').str.split(',', expand=True)

                      0     1     2         3
P_ID N_ID                                    
1    A1   Result  pos    +     pos   positive
          Gene    kras   kras  kras  egfr    
2    A2   Result  neg    neg   None  None    
          Gene    brca   brca  None  None    
3    A3   Result         None  None  None    
          Gene           None  None  None    
4    A4   Result  pos    None  None  None    
          Gene    cd133  None  None  None    

我们需要删除 NULL 值,因此再次调用

stack

_.stack()

P_ID  N_ID           
1     A1    Result  0    pos     
                    1    +       
                    2    pos     
                    3    positive
            Gene    0    kras    
                    1    kras    
                    2    kras    
                    3    egfr    
2     A2    Result  0    neg     
                    1    neg     
            Gene    0    brca    
                    1    brca    
3     A3    Result  0            
            Gene    0            
4     A4    Result  0    pos     
            Gene    0    cd133   
dtype: object

我们就快到了。现在我们希望索引的倒数第二层成为我们的列,因此使用

unstack(-2)
取消堆叠(倒数第二层上的
unstack

_.unstack(-2)

               Result   Gene
P_ID N_ID                   
1    A1   0  pos       kras 
          1  +         kras 
          2  pos       kras 
          3  positive  egfr 
2    A2   0  neg       brca 
          1  neg       brca 
3    A3   0                 
4    A4   0  pos       cd133

最后,需要做一些整理工作才能获得我们的原始专栏。

_.reset_index(-1, drop=True).reset_index()

   P_ID N_ID    Result   Gene
0  1     A1   pos       kras 
1  1     A1   +         kras 
2  1     A1   pos       kras 
3  1     A1   positive  egfr 
4  2     A2   neg       brca 
5  2     A2   neg       brca 
6  3     A3                  
7  4     A4   pos       cd133

如果您希望空白实际上是列表,请使用

applymap
:

_.applymap(lambda x: x if x != '' else []))

   P_ID N_ID    Result   Gene
0  1     A1   pos       kras 
1  1     A1   +         kras 
2  1     A1   pos       kras 
3  1     A1   positive  egfr 
4  2     A2   neg       brca 
5  2     A2   neg       brca 
6  3     A3   []        []   
7  4     A4   pos       cd133

2
投票

调整后

unnesting
仍然有效

df=df.applymap(lambda x : [''] if x==[] else x)
unnesting(df,['Gene','Result'])
Out[20]: 
    Gene    Result N_ID  P_ID
0   kras       pos   A1     1
0   kras         +   A1     1
0   kras       pos   A1     1
0   egfr  positive   A1     1
1   brca       neg   A2     2
1   brca       neg   A2     2
2                    A3     3
3  cd133       pos   A4     4

0
投票

新版本修复了吗?您可以使用

explode
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html

>>> df = pd.DataFrame({'A': [[0, 1, 2], 'foo', [], [3, 4]],
...                    'B': 1,
...                    'C': [['a', 'b', 'c'], np.nan, [], ['d', 'e']]})
>>> df
           A  B          C
0  [0, 1, 2]  1  [a, b, c]
1        foo  1        NaN
2         []  1         []
3     [3, 4]  1     [d, e]

爆炸

>>> df.explode(list('AC'))
     A  B    C
0    0  1    a
0    1  1    b
0    2  1    c
1  foo  1  NaN
2  NaN  1  NaN
3    3  1    d
3    4  1    e
© www.soinside.com 2019 - 2024. All rights reserved.