[英]Split a Pandas column of lists into multiple columns
我有一个 Pandas DataFrame 与一列:
import pandas as pd
df = pd.DataFrame({"teams": [["SF", "NYG"] for _ in range(7)]})
teams
0 [SF, NYG]
1 [SF, NYG]
2 [SF, NYG]
3 [SF, NYG]
4 [SF, NYG]
5 [SF, NYG]
6 [SF, NYG]
如何将这一列列表拆分为两列?
期望的结果:
team1 team2
0 SF NYG
1 SF NYG
2 SF NYG
3 SF NYG
4 SF NYG
5 SF NYG
6 SF NYG
您可以将
DataFrame<\/code>构造函数与
lists<\/code>创建的列表
to_list<\/code><\/a>使用:
import pandas as pd
d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
df2 = pd.DataFrame(d1)
print (df2)
teams
0 [SF, NYG]
1 [SF, NYG]
2 [SF, NYG]
3 [SF, NYG]
4 [SF, NYG]
5 [SF, NYG]
6 [SF, NYG]
更简单的解决方案:
pd.DataFrame(df2["teams"].to_list(), columns=['team1', 'team2'])
产量,
team1 team2
-------------
0 SF NYG
1 SF NYG
2 SF NYG
3 SF NYG
4 SF NYG
5 SF NYG
6 SF NYG
7 SF NYG
如果您想拆分一列分隔字符串而不是列表,您可以类似地执行以下操作:
pd.DataFrame(df["teams"].str.split('<delim>', expand=True).values,
columns=['team1', 'team2'])
与使用
tolist()<\/code>的任何解决方案不同,此解决方案保留了
df2<\/code> DataFrame 的索引:
df3 = df2.teams.apply(pd.Series)
df3.columns = ['team1', 'team2']
与建议的解决方案相反,似乎有一种语法上更简单的方法,因此更容易记住。 我假设该列在数据框 df 中称为“元”:
df2 = pd.DataFrame(df['meta'].str.split().values.tolist())
以前的解决方案对我不起作用,因为我的
dataframe<\/code>有
nan<\/code>观察结果。
在我的情况下
df2[['team1','team2']] = pd.DataFrame(df2.teams.values.tolist(), index= df2.index)<\/code>产生:
object of type 'float' has no len()
列表理解
一个简单的列表理解实现(我最喜欢的)
df = pd.DataFrame([pd.Series(x) for x in df.teams])
df.columns = ['team_{}'.format(x+1) for x in df.columns]
输出时序:
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 2.71 ms
输出:
team_1 team_2
0 SF NYG
1 SF NYG
2 SF NYG
3 SF NYG
4 SF NYG
5 SF NYG
6 SF NYG
这是使用
df.transform<\/code><\/a>和
df.set_index<\/code><\/a>的另一个解决方案:
>>> from operator import itemgetter
>>> df['teams'].transform({'item1': itemgetter(0), 'item2': itemgetter(1)})
team1 team2
0 SF NYG
1 SF NYG
2 SF NYG
3 SF NYG
4 SF NYG
5 SF NYG
6 SF NYG
根据之前的答案,这是另一个解决方案,它返回与 df2.teams.apply(pd.Series) 相同的结果,运行时间更快:
pd.DataFrame([{x: y for x, y in enumerate(item)} for item in df2['teams'].values.tolist()], index=df2.index)
时间:
In [1]:
import pandas as pd
d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
df2 = pd.DataFrame(d1)
df2 = pd.concat([df2]*1000).reset_index(drop=True)
In [2]: %timeit df2['teams'].apply(pd.Series)
8.27 s ± 2.73 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [3]: %timeit pd.DataFrame([{x: y for x, y in enumerate(item)} for item in df2['teams'].values.tolist()], index=df2.index)
35.4 ms ± 5.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
我想推荐一种更有效和 Pythonic 的方式。
首先将 DataFrame 定义为原始帖子:
df = pd.DataFrame({"teams": [["SF", "NYG"] for _ in range(7)]})
如果有人来这里找一个现成的function,我写了一个。
columns
,它会查找所有带有列表的列并展开它们;column_name_0
、 column_name_1
等的列;strict=True
,它检查给定列中的列表是否大小相等。改进和评论表示赞赏。
def unfold_columns(df, columns=[], strict=False):
assert isinstance(columns, list), "Columns should be a list of column names"
if len(columns) == 0:
columns = [
column for column in df.columns
if df.applymap(lambda x: isinstance(x, list)).all()[column]
]
else:
assert(all([(column in df.columns) for column in columns])), \
"Not all given columns are found in df"
columns_order = df.columns
for column_name in columns:
if df[column_name].apply(lambda x: isinstance(x, list)).all():
if strict:
assert len(set(df[column_name].apply(lambda x: len(x)))) == 1, \
f"Lists in df['{column_name}'] are not of equal length"
unfolded = pd.DataFrame(df[column_name].tolist())
unfolded.columns = [f'{column_name}_{x}' for x in unfolded.columns]
columns_order = [
*columns_order[:list(columns_order).index(column_name)],
*unfolded.columns,
*columns_order[list(columns_order).index(column_name)+1:]
]
df = df.join(unfolded).drop([column_name], axis=1)
return df[columns_order]
您可以尝试使用两次 apply 在您的 df 中创建新列 'team1' 和 'team2'
df = pd.DataFrame({"teams": [["SF", "NYG"] for _ in range(7)]})
df["team1"]=df['teams'].apply(lambda x: x[0] )
df["team2"]=df['teams'].apply(lambda x: x[1] )
df
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.