San*_*dav 20 python expand list dataframe pandas
我在熊猫中有这样的数据框:
column1 column2
[a,b,c] 1
[d,e,f] 2
[g,h,i] 3
Run Code Online (Sandbox Code Playgroud)
column1 column2
a 1
b 1
c 1
d 2
e 2
f 2
g 3
h 3
i 3
Run Code Online (Sandbox Code Playgroud)
如何处理这些数据?
Erf*_*fan 46
DataFrame.explode因为pandas >= 0.25.0我们有这个explode方法,它将列表扩展为每个元素的一行并重复其余的列:
df.explode('column1').reset_index(drop=True)
Run Code Online (Sandbox Code Playgroud)
输出
column1 column2
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2
6 g 3
7 h 3
8 i 3
Run Code Online (Sandbox Code Playgroud)
由于pandas >= 1.1.0我们有ignore_index参数,所以我们不必链接reset_index:
df.explode('column1', ignore_index=True)
Run Code Online (Sandbox Code Playgroud)
输出
column1 column2
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2
6 g 3
7 h 3
8 i 3
Run Code Online (Sandbox Code Playgroud)
jez*_*ael 20
您可以DataFrame通过其构造函数创建并stack:
df2 = pd.DataFrame(df.column1.tolist(), index=df.column2)
.stack()
.reset_index(level=1, drop=True)
.reset_index(name='column1')[['column1','column2']]
print (df2)
column1 column2
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2
6 g 3
7 h 3
8 i 3
Run Code Online (Sandbox Code Playgroud)
如果需要按子集更改排序[['column1','column2']],您还可以先省略reset_index:
df2 = pd.DataFrame(df.column1.tolist(), index=df.column2)
.stack()
.reset_index(name='column1')[['column1','column2']]
print (df2)
column1 column2
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2
6 g 3
7 h 3
8 i 3
Run Code Online (Sandbox Code Playgroud)
另一种解决方案DataFrame.from_records,用于创建DataFrame从第一列,然后创建Series通过stack与join原始DataFrame:
df = pd.DataFrame({'column1': [['a','b','c'],['d','e','f'],['g','h','i']],
'column2':[1,2,3]})
a = pd.DataFrame.from_records(df.column1.tolist())
.stack()
.reset_index(level=1, drop=True)
.rename('column1')
print (a)
0 a
0 b
0 c
1 d
1 e
1 f
2 g
2 h
2 i
Name: column1, dtype: object
print (df.drop('column1', axis=1)
.join(a)
.reset_index(drop=True)[['column1','column2']])
column1 column2
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2
6 g 3
7 h 3
8 i 3
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是使用自pandas 0.23起可用result_type='expand'的pandas.apply函数的参数。回答@splinter的问题,此方法可以推广-参见下文:
import pandas as pd
from numpy import arange
df = pd.DataFrame(
{'column1' : [['a','b','c'],['d','e','f'],['g','h','i']],
'column2': [1,2,3]}
)
pd.melt(
df.join(
df.apply(lambda row: row['column1'], axis=1, result_type='expand')
),
value_vars=arange(df['column1'].shape[0]), value_name='column1', var_name='column2')[['column1','column2']]
# can be generalized
df = pd.DataFrame(
{'column1' : [['a','b','c'],['d','e','f'],['g','h','i']],
'column2': [1,2,3],
'column3': [[1,2],[2,3],[3,4]],
'column4': [42,23,321],
'column5': ['a','b','c']}
)
(pd.melt(
df.join(
df.apply(lambda row: row['column1'], axis=1, result_type='expand')
),
value_vars=arange(df['column1'].shape[0]), value_name='column1', id_vars=df.columns[1:])
.drop(columns=['variable'])[list(df.columns[:1]) + list(df.columns[1:])]
.sort_values(by=['column1']))
Run Code Online (Sandbox Code Playgroud)
更新(Jwely的评论):如果列表的长度不同,则可以执行以下操作:
df = pd.DataFrame(
{'column1' : [['a','b','c'],['d','f'],['g','h','i']],
'column2': [1,2,3]}
)
longest = max(df['column1'].apply(lambda x: len(x)))
pd.melt(
df.join(
df.apply(lambda row: row['column1'] if len(row['column1']) >= longest else row['column1'] + [None] * (longest - len(row['column1'])), axis=1, result_type='expand')
),
value_vars=arange(df['column1'].shape[0]), value_name='column1', var_name='column2').query("column1 == column1")[['column1','column2']]
Run Code Online (Sandbox Code Playgroud)