Python 在数据帧中取消(分解)多个列表列的有效方法

Python 在数据帧中取消(分解)多个列表列的有效方法,python,json,pandas,dataframe,Python,Json,Pandas,Dataframe,我正在将多个JSON对象读入一个数据帧。问题是有些列是列表。此外,数据非常大,因此我无法使用互联网上可用的解决方案。它们速度很慢,内存效率也很低 以下是我的数据的外观: df = pd.DataFrame({'A': ['x1','x2','x3', 'x4'], 'B':[['v1','v2'],['v3','v4'],['v5','v6'],['v7','v8']], 'C':[['c1','c2'],['c3','c4'],['c5','c6'],['c7','c8']],'D':[['d

我正在将多个JSON对象读入一个数据帧。问题是有些列是列表。此外,数据非常大,因此我无法使用互联网上可用的解决方案。它们速度很慢,内存效率也很低

以下是我的数据的外观:

df = pd.DataFrame({'A': ['x1','x2','x3', 'x4'], 'B':[['v1','v2'],['v3','v4'],['v5','v6'],['v7','v8']], 'C':[['c1','c2'],['c3','c4'],['c5','c6'],['c7','c8']],'D':[['d1','d2'],['d3','d4'],['d5','d6'],['d7','d8']], 'E':[['e1','e2'],['e3','e4'],['e5','e6'],['e7','e8']]})
    A       B          C           D           E
0   x1  [v1, v2]    [c1, c2]    [d1, d2]    [e1, e2]
1   x2  [v3, v4]    [c3, c4]    [d3, d4]    [e3, e4]
2   x3  [v5, v6]    [c5, c6]    [d5, d6]    [e5, e6]
3   x4  [v7, v8]    [c7, c8]    [d7, d8]    [e7, e8]
这是我数据的形状:(441079,12)

我期望的输出是:

    A       B          C           D           E
0   x1      v1         c1         d1          e1
0   x1      v2         c2         d2          e2
1   x2      v3         c3         d3          e3
1   x2      v4         c4         d4          e4
.....

编辑:在被标记为重复之后,我想强调一个事实,在这个问题中,我正在寻找一种分解多个列的有效方法。因此,经批准的答案能够在非常大的数据集上有效地分解任意数量的列。另一个问题的答案没有做到的事情(这就是我在测试这些解决方案后问这个问题的原因)。

使用
A
上设置索引
,并在剩余列
上应用
堆栈
值。所有这些都浓缩成一行

In [1253]: (df.set_index('A')
              .apply(lambda x: x.apply(pd.Series).stack())
              .reset_index()
              .drop('level_1', 1))
Out[1253]:
    A   B   C   D   E
0  x1  v1  c1  d1  e1
1  x1  v2  c2  d2  e2
2  x2  v3  c3  d3  e3
3  x2  v4  c4  d4  e4
4  x3  v5  c5  d5  e5
5  x3  v6  c6  d6  e6
6  x4  v7  c7  d7  e7
7  x4  v8  c8  d8  e8
用法:

In [82]: explode(df, lst_cols=list('BCDE'))
Out[82]:
    A   B   C   D   E
0  x1  v1  c1  d1  e1
1  x1  v2  c2  d2  e2
2  x2  v3  c3  d3  e3
3  x2  v4  c4  d4  e4
4  x3  v5  c5  d5  e5
5  x3  v6  c6  d6  e6
6  x4  v7  c7  d7  e7
7  x4  v8  c8  d8  e8
熊猫>=0.25 假设所有列都有相同数量的列表,您可以调用每个列

df.set_index(['A']).apply(pd.Series.explode).reset_index()

    A   B   C   D   E
0  x1  v1  c1  d1  e1
1  x1  v2  c2  d2  e2
2  x2  v3  c3  d3  e3
3  x2  v4  c4  d4  e4
4  x3  v5  c5  d5  e5
5  x3  v6  c6  d6  e6
6  x4  v7  c7  d7  e7
7  x4  v8  c8  d8  e8
其思想是将所有必须首先分解的列设置为索引,然后重置索引


它的速度也更快

%timeit df.set_index(['A']).apply(pd.Series.explode).reset_index()
%%timeit
(df.set_index('A')
   .apply(lambda x: x.apply(pd.Series).stack())
   .reset_index()
   .drop('level_1', 1))


2.22 ms ± 98.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9.14 ms ± 329 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

基于@cs95的答案,我们可以在
lambda
函数中使用
if
子句,而不是将所有其他列设置为
索引。这有以下优点:

  • 保留列顺序
  • 允许您使用要修改的集合,即[…]中的
    x.name
    ,或不在[…]中修改
    x.name,轻松指定列

是的,如果有包含Python
list
s的
object
dtype列,那么一切都会很慢,内存效率也会很低。如果从一开始就不创建这样的数据帧,那么问题可能会得到更好的解决。@juanpa.arrivillaga我可以用不同的方式读取JSON文件而不造成这种混乱吗?pd.read_csv有定义转换器的选项,但我找不到与pd.read_jsony类似的东西。您可能需要编写一些东西,将反序列化的json数据转换为更易于管理的内容。@juanpa.arrivillaga出乎我的意料,答案是超级高效的!相关报道:我非常喜欢这个简单的答案。我曾尝试过类似的方法,但没能成功这是一个很好的答案!一个小建议是将最后两个命令组合为:
.reset\u index(level=1,drop=True)
如果@bnaul不起作用,您需要另外一个:
.reset\u index(level=1,drop=True)。reset\u index()
这是@cs95在相同或不同大小的列表上回答的一般形式。我们有一个问题:如果你愿意,你可以发布你的impl。如果它被测试为PR,那么IMO应该被标记为答案,感谢您在我的测试中分享,当不同列中的列表大小不相同时,此解决方案不起作用。否则它就像一个符咒!事实上,因此第1句中的免责声明。这个答案很好。适用于相同长度的列。如果长度不一样,那么我认为无论如何都不会有任何标准答案;这取决于你如何处理它。谢谢@CS95这给了我
ValueError:无法处理非唯一的多索引然而,@Zero下面的答案很有魅力。
%timeit df.set_index(['A']).apply(pd.Series.explode).reset_index()
%%timeit
(df.set_index('A')
   .apply(lambda x: x.apply(pd.Series).stack())
   .reset_index()
   .drop('level_1', 1))


2.22 ms ± 98.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9.14 ms ± 329 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
df.apply(lambda x: x.explode() if x.name in ['B', 'C', 'D', 'E'] else x)

     A   B   C   D   E
0   x1  v1  c1  d1  e1
0   x1  v2  c2  d2  e2
1   x2  v3  c3  d3  e3
1   x2  v4  c4  d4  e4
2   x3  v5  c5  d5  e5
2   x3  v6  c6  d6  e6
3   x4  v7  c7  d7  e7
3   x4  v8  c8  d8  e8