将多列拆分为 pandas 数据框中的行
Splitting multiple columns into rows in pandas dataframe
我有一个 pandas 数据框如下:
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
非常感谢任何帮助。
你可以先split
columns, create Series
by stack
and remove whitespaces by 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
我经常注意到这个问题。也就是说,如何将具有列表的这一列拆分为多行?我见过它叫做爆炸。以下是一些链接:
所以我写了一个函数来完成它。
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 行样本
我根据之前的回答写了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|
+-----------+------+-----+--------+
因为我太新了,不让写评论,所以写一个"answer"。
@titipata 你的答案非常有效,但我认为你的代码中有一小部分 "mistake" 我自己找不到。
我使用这个问题中的示例并仅更改了值。
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
如您所见,在列 'electronic' 中,“1”行中的值应为“1”而不是“2.1”。
因此,洞数据集会发生变化。我希望有人能帮我找到解决办法。
Pandas >= 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
我有一个 pandas 数据框如下:
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
非常感谢任何帮助。
你可以先split
columns, create Series
by stack
and remove whitespaces by 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
我经常注意到这个问题。也就是说,如何将具有列表的这一列拆分为多行?我见过它叫做爆炸。以下是一些链接:
所以我写了一个函数来完成它。
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 行样本
我根据之前的回答写了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|
+-----------+------+-----+--------+
因为我太新了,不让写评论,所以写一个"answer"。
@titipata 你的答案非常有效,但我认为你的代码中有一小部分 "mistake" 我自己找不到。
我使用这个问题中的示例并仅更改了值。
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
如您所见,在列 'electronic' 中,“1”行中的值应为“1”而不是“2.1”。
因此,洞数据集会发生变化。我希望有人能帮我找到解决办法。
Pandas >= 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