如何在 Python Pandas 中扩展存储为单个值的可迭代对象? (又名反向分组)[重复]

Posted

技术标签:

【中文标题】如何在 Python Pandas 中扩展存储为单个值的可迭代对象? (又名反向分组)[重复]【英文标题】:How to expand an iterable stored as a single value in Python Pandas? (a.k.a. reverse groupby) [duplicate] 【发布时间】:2021-10-24 00:22:57 【问题描述】:

我有以下数据框:

Index Letter Numbers
1     A      [1, 11]
2     B      [2, 22]
3     C      [3, 33]

我想“扩展”数字列表,这样每个数字都有自己的行,如下所示:

Index Letter Numbers
1     A      1
2     A      11
3     B      2
4     B      22
5     C      3
6     C      33

我尝试使用以下代码来实现这一点:

import pandas as pd

df = pd.DataFrame(
    'Letter': ['A', 'B', 'C'],
    'Numbers': [[1, 11], [2, 22], [3, 33]]
)

for i, row in df.iterrows():
    for num in row['Numbers']:
        new_row = row.copy()
        new_row['Numbers'] = num
        df = df.append(new_row, ignore_index=True)

df = df.loc[df.apply(lambda x: type(x['Numbers']) != list, axis=1)]

它适用于示例,但在更大的 DataFrame(例如几十万行)中需要很多时间。有没有更好、更优化的方法来做到这一点?我尝试使用 apply 方法,但由于某种原因它清除了我的 DataFrame...

【问题讨论】:

使用explode:df.explode('Numbers') explode 是最用户友好的选项。但它可能会很慢,因为这样的操作不能很好地扩展。如果性能是一个真正的要求,有一些方法可以使用numpy 来重构 DataFrame。如果您知道所有列表的大小都相同,则可能非常简单,否则您需要非常小心,并且可能会变得有点混乱 【参考方案1】:

使用explode 垂直扩展值:

>>> df.explode('Numbers', ignore_index=True)

  Letter Numbers
0      A       1
1      A      11
2      B       2
3      B      22
4      C       3
5      C      33

使用apply(pd.Series) 水平扩展值:


>>> df.join(df['Numbers'].apply(pd.Series)
                         .add_prefix('Numbers_')) \
      .drop(columns='Numbers')

  Letter  Numbers_0  Numbers_1
0      A          1         11
1      B          2         22
2      C          3         33

【讨论】:

【参考方案2】:

正如 cmets 中已经提到的,如果您没有大量数据要解析,那么使用 df.explode() 真的很容易

>>> df
  Letter  Numbers
0      A  [1, 11]
1      B  [2, 22]
2      C  [3, 33]

解决方案 1

>>> df = df.explode('Numbers')
>>> df
  Letter Numbers
0      A       1
0      A      11
1      B       2
1      B      22
2      C       3
2      C      33

解决方案 2:

np.repeat 会更快...

>>> lens = [len(item) for item in df['Numbers']]
>>> pd.DataFrame( "Letter" : np.repeat(df['Letter'].values,lens), "Numbers" : np.hstack(df['Numbers']))
  Letter  Numbers
0      A        1
1      A       11
2      B        2
3      B       22
4      C        3
5      C       33

其他解决方案..

df.explode('Numbers', ignore_index=True)
# df.explode('Numbers').reset_index(drop=True)

  Letter Numbers
0      A       1
1      A      11
2      B       2
3      B      22
4      C       3
5      C      33

使用 apply + pd.Series

 >>> df.set_index('Letter').Numbers.apply(pd.Series).stack().reset_index(level=0).rename(columns=0:'Numbers')
  Letter  Numbers
0      A        1
1      A       11
0      B        2
1      B       22
0      C        3
1      C       33

注意:

同时,我已经看到了同样here another Solutions 的有趣答案

编码愉快!

【讨论】:

以上是关于如何在 Python Pandas 中扩展存储为单个值的可迭代对象? (又名反向分组)[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何更新python中如pandas等的扩展

Pandas:如何将 cProfile 输出存储在 pandas DataFrame 中?

如何让空值不存储在 Pandas Python 中的 HBase 中?

Pandas/Python 如何存储循环值

如何在 Python 中将 WAV 从立体声转换为单声道?

如何使用 Pandas 或 Requests 在 Python 中访问私有 Github Repo 文件 (.csv)