在熊猫数据框中将多列拆分为行

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)

然后concatSeriesdf1

df1 = pd.concat([s1,s2], axis=1, keys=['value','date'])

删除旧列 valuedatejoin

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

拆分 valuedate 列:

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 很慢,但另一方面有很多操作,如 stackconcatjoin,所以也许这可以是可比。 我发现解决方案有所不同 - 我使用 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 会发生变化。我希望有人可以帮助我找到解决方案。

【讨论】:

以上是关于在熊猫数据框中将多列拆分为行的主要内容,如果未能解决你的问题,请参考以下文章

在熊猫中将多列合并为一列

熊猫在循环中将多列相乘

合并两个具有共同值的熊猫数据框,这些数据框在一个数据框中显示为列,而在另一个数据框中显示为行

将熊猫多索引数据框重塑为多列

如何绘制熊猫数据框的多列

matplotlib:在条形图上绘制多列熊猫数据框