背景
我有以下数据框
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
问题
如何获得所需的输出?
让我们尝试一些堆叠和拆垛魔法。这也保留了空列表。
(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
调整后
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
新版本修复了吗?您可以使用
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