看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
爆炸这个词非常形象,是指将类似列表的每个元素转换为一行,索引值是相同的,就这么简单,下边直接上代码。这个操作也叫 unnest (explode)。
下边的两行数据中有类似列表(list-likes,包括 lists, tuples, sets, Series 和 np.ndarray)的值,我们将它们炸开后,它他乖乖回去排好了队,但是依然使用原来的索引:
s = pd.Series([[1, 2, 3], 'foo', [], [3, 4]])
s
'''
0 [1, 2, 3]
1 foo
2 []
3 [3, 4]
dtype: object
'''
s.explode()
'''
0 1
0 2
0 3
1 foo
2 NaN
3 3
3 4
dtype: object
'''
子集行的结果 dtype 将为 object。 标量将原封不动地返回,并且空列表状将导致该行的 np.nan。 此外,爆炸集合时,输出中行的顺序将不确定。
我们看到,对指定列进行了炸裂:
df = pd.DataFrame({'A': [[1, 2, 3], 'foo', [], [3, 4]], 'B': 1})
'''
df
A B
0 [1, 2, 3] 1
1 foo 1
2 [] 1
3 [3, 4] 1
'''
df.explode('A')
'''
A B
0 1 1
0 2 1
0 3 1
1 foo 1
2 NaN 1
3 3 1
3 4 1
'''
Pandas 1.3.0 开始支持多列的炸开:
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]
'''
# A、C 两列执行
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
'''
有时候遇到不是列表的,但是具有列表的特质,我们也可以处理:
df = pd.DataFrame([{'var1': 'a,b,c', 'var2': 1},
{'var1': 'd,e,f', 'var2': 2}])
df
'''
var1 var2
0 a,b,c 1
1 d,e,f 2
'''
看看 var1 列,我们发现可以处理成列表:
df.assign(var1=df.var1.str.split(',')).explode('var1')
'''
var1 var2
0 a 1
0 b 1
0 c 1
1 d 2
1 e 2
1 f 2
'''
以上的操作都是竖向爆炸,如果想横向爆炸,可以考虑使用以下方法。
import pandas as pd
df = pd.DataFrame(
dict(
name=['A', 'B', 'C', 'D'],
age=[10, 20, 30, 40],
code=[['c1', 'c2'], ['c2', 'c3'], ['c1'], ['c1', 'c3']]
)
)
df
'''
name age code
0 A 10 [c1, c2]
1 B 20 [c2, c3]
2 C 30 [c1]
3 D 40 [c1, c3]
'''
先对列应用 pd.Series 构造为多列 DataFrame,也可以直接将此列转为列表,现用 pd.DataFrame() 构造:
temp = df.code.apply(pd.Series).add_prefix('code_')
temp = pd.DataFrame(df.code.to_list()).add_prefix(f'{df.code.name}_')
temp
'''
code_0 code_1
0 c1 c2
1 c2 c3
2 c1 NaN
3 c1 c3
'''
再和原数据拼接起来
pd.concat([df, temp], axis=1)
'''
name age code code_0 code_1
0 A 10 [c1, c2] c1 c2
1 B 20 [c2, c3] c2 c3
2 C 30 [c1] c1 NaN
3 D 40 [c1, c3] c1 c3
'''
如果内容不是一个原生的字典,可以考虑使用类似 ser.str.split('_', expand=True)
的方法,详见教程:pandas 文本分割。
更新时间:2024-08-11 11:39:01 标签:pandas 列表