在熊猫数据框中将多列拆分为行
Posted
技术标签:
【中文标题】在熊猫数据框中将多列拆分为行【英文标题】:Splitting multiple columns into rows in pandas dataframe 【发布时间】:2016-12-03 17:02:29 【问题描述】:我有一个熊猫数据框如下:
ticker account value date
aa assets 100,200 20121231, 20131231
bb liabilities 50, 150 20141231, 20131231
我想拆分 df['value']
和 df['date']
以便数据框如下所示:
ticker account value date
aa assets 100 20121231
aa assets 200 20131231
bb liabilities 50 20141231
bb liabilities 150 20131231
非常感谢任何帮助。
【问题讨论】:
重复问题:***.com/q/45846765/6660373 这能回答你的问题吗? Efficient way to unnest (explode) multiple list columns in a pandas DataFrame 【参考方案1】:您可以先split
列,通过stack
创建Series
并通过strip
删除空格:
s1 = df.value.str.split(',', expand=True).stack().str.strip().reset_index(level=1, drop=True)
s2 = df.date.str.split(',', expand=True).stack().str.strip().reset_index(level=1, drop=True)
然后concat
Series
到df1
:
df1 = pd.concat([s1,s2], axis=1, keys=['value','date'])
删除旧列 value
和 date
和 join
:
print (df.drop(['value','date'], axis=1).join(df1).reset_index(drop=True))
ticker account value date
0 aa assets 100 20121231
1 aa assets 200 20131231
2 bb liabilities 50 20141231
3 bb liabilities 150 20131231
【讨论】:
感谢 jezrael 和 piRSquared 的两个答案! jezrael,你的方法很有效。【参考方案2】:我经常注意到这个问题。也就是说,如何将这个有列表的列拆分为多行?我见过它叫爆炸。以下是一些链接:
https://***.com/a/38432346/2336654 https://***.com/a/38499036/2336654所以我写了一个函数来完成它。
def explode(df, columns):
idx = np.repeat(df.index, df[columns[0]].str.len())
a = df.T.reindex_axis(columns).values
concat = np.concatenate([np.concatenate(a[i]) for i in range(a.shape[0])])
p = pd.DataFrame(concat.reshape(a.shape[0], -1).T, idx, columns)
return pd.concat([df.drop(columns, axis=1), p], axis=1).reset_index(drop=True)
但在我们可以使用它之前,我们需要列中的列表(或可迭代的)。
设置
df = pd.DataFrame([['aa', 'assets', '100,200', '20121231,20131231'],
['bb', 'liabilities', '50,50', '20141231,20131231']],
columns=['ticker', 'account', 'value', 'date'])
df
拆分 value
和 date
列:
df.value = df.value.str.split(',')
df.date = df.date.str.split(',')
df
现在我们可以在任一列或两列上展开,一个接一个。
解决方案
explode(df, ['value','date'])
时间
我从@jezrael 的时间中删除了strip
,因为我无法有效地将它添加到我的。这是此问题的必要步骤,因为 OP 在逗号后的字符串中有空格。我的目标是提供一种通用的方法来分解一个列,因为它已经包含了可迭代对象,我想我已经做到了。
代码
def get_df(n=1):
return pd.DataFrame([['aa', 'assets', '100,200,200', '20121231,20131231,20131231'],
['bb', 'liabilities', '50,50', '20141231,20131231']] * n,
columns=['ticker', 'account', 'value', 'date'])
小 2 行样本
中等 200 行样本
2,000,000 行大样本
【讨论】:
我对时间很好奇 ;)iterritems
很慢,但另一方面有很多操作,如 stack
、concat
和 join
,所以也许这可以是可比。
我发现解决方案有所不同 - 我使用 strip
。您也可以将其添加到您的解决方案中,然后再次尝试计时吗?我想你忘记了。
@jezrael 已更新。请注意我在###Timing 下方写的内容【参考方案3】:
我根据之前的答案编写了explode
函数。它可能对任何想要快速抓取和使用它的人有用。
def explode(df, cols, split_on=','):
"""
Explode dataframe on the given column, split on given delimeter
"""
cols_sep = list(set(df.columns) - set(cols))
df_cols = df[cols_sep]
explode_len = df[cols[0]].str.split(split_on).map(len)
repeat_list = []
for r, e in zip(df_cols.as_matrix(), explode_len):
repeat_list.extend([list(r)]*e)
df_repeat = pd.DataFrame(repeat_list, columns=cols_sep)
df_explode = pd.concat([df[col].str.split(split_on, expand=True).stack().str.strip().reset_index(drop=True)
for col in cols], axis=1)
df_explode.columns = cols
return pd.concat((df_repeat, df_explode), axis=1)
@piRSquared 给出的示例:
df = pd.DataFrame([['aa', 'assets', '100,200', '20121231,20131231'],
['bb', 'liabilities', '50,50', '20141231,20131231']],
columns=['ticker', 'account', 'value', 'date'])
explode(df, ['value', 'date'])
输出
+-----------+------+-----+--------+
| account|ticker|value| date|
+-----------+------+-----+--------+
| assets| aa| 100|20121231|
| assets| aa| 200|20131231|
|liabilities| bb| 50|20141231|
|liabilities| bb| 50|20131231|
+-----------+------+-----+--------+
【讨论】:
【参考方案4】:熊猫 >= 0.25
df.value = df.value.str.split(',')
df.date = df.date.str.split(',')
df = df.explode('value').explode("date").reset_index(drop=True)
df:
ticker account value date
0 aa assets 100 20121231
1 aa assets 100 20131231
2 aa assets 200 20121231
3 aa assets 200 20131231
4 bb liabilities 50 20141231
5 bb liabilities 50 20131231
6 bb liabilities 50 20141231
7 bb liabilities 50 20131231
【讨论】:
【参考方案5】:因为我太新了,不让我写评论,所以我写了一个“答案”。
@titipata 您的回答非常好,但我认为您的代码中有一个小“错误”,我无法为自己找到。
我使用此问题中的示例并仅更改了值。
df = pd.DataFrame([['title1', 'publisher1', '1.1,1.2', '1'],
['title2', 'publisher2', '2', '2.1,2.2']],
columns=['titel', 'publisher', 'print', 'electronic'])
explode(df, ['print', 'electronic'])
publisher titel print electronic
0 publisher1 title1 1.1 1
1 publisher1 title1 1.2 2.1
2 publisher2 title2 2 2.2
如您所见,在“电子”列中,“1”行中的值应为“1”而不是“2.1”。
正因为如此,hole DataSet 会发生变化。我希望有人可以帮助我找到解决方案。
【讨论】:
以上是关于在熊猫数据框中将多列拆分为行的主要内容,如果未能解决你的问题,请参考以下文章