我有以下数据帧,其中一列是一个对象(列表类型单元格):

df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})

输出:

   A       B
0  1  [1, 2]
1  2  [1, 2]

我的期望输出是:

   A  B
0  1  1
1  1  2
3  2  1
4  2  2

我该怎么做才能做到这一点呢?


相关的问题

Pandas列的列表,为每个列表元素创建一行

很好的问题和答案,但只处理一个列与列表(在我的回答自定义函数将工作于多个列,也接受的答案是使用最耗时的应用,这是不建议的,检查更多信息当我(不)想要使用熊猫应用()在我的代码?)


当前回答

我有另一个好方法来解决这个问题当你有不止一列要爆炸的时候。

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]], 'C':[[1,2,3],[1,2,3]]})

print(df)
   A       B          C
0  1  [1, 2]  [1, 2, 3]
1  2  [1, 2]  [1, 2, 3]

我想爆炸B和C列,首先爆炸B,第二爆炸C,然后从原来的df中去掉B和C。之后,我将在3个dfs上做一个索引连接。

explode_b = df.explode('B')['B']
explode_c = df.explode('C')['C']
df = df.drop(['B', 'C'], axis=1)
df = df.join([explode_b, explode_c])

其他回答

一种替代方法是在列的行上应用meshgrid recipe来取消嵌套:

import numpy as np
import pandas as pd


def unnest(frame, explode):
    def mesh(values):
        return np.array(np.meshgrid(*values)).T.reshape(-1, len(values))

    data = np.vstack(mesh(row) for row in frame[explode].values)
    return pd.DataFrame(data=data, columns=explode)


df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})
print(unnest(df, ['A', 'B']))  # base
print()

df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [3, 4]], 'C': [[1, 2], [3, 4]]})
print(unnest(df, ['A', 'B', 'C']))  # multiple columns
print()

df = pd.DataFrame({'A': [1, 2, 3], 'B': [[1, 2], [1, 2, 3], [1]],
                   'C': [[1, 2, 3], [1, 2], [1, 2]], 'D': ['A', 'B', 'C']})

print(unnest(df, ['A', 'B']))  # uneven length lists
print()
print(unnest(df, ['D', 'B']))  # different types
print()

输出

   A  B
0  1  1
1  1  2
2  2  1
3  2  2

   A  B  C
0  1  1  1
1  1  2  1
2  1  1  2
3  1  2  2
4  2  3  3
5  2  4  3
6  2  3  4
7  2  4  4

   A  B
0  1  1
1  1  2
2  2  1
3  2  2
4  2  3
5  3  1

   D  B
0  A  1
1  A  2
2  B  1
3  B  2
4  B  3
5  C  1

在pandas 0.25中,由于增加了explosion()方法,爆炸一个类似列表的列被大大简化了:

df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})
df.explode('B')

Out:

   A  B
0  1  1
0  1  2
1  2  1
1  2  2

有些东西不太推荐(至少在这种情况下有用):

df=pd.concat([df]*2).sort_index()
it=iter(df['B'].tolist()[0]+df['B'].tolist()[0])
df['B']=df['B'].apply(lambda x:next(it))

Concat + sort_index + iter + apply + next。

Now:

print(df)

Is:

   A  B
0  1  1
0  1  2
1  2  1
1  2  2

如果关心索引:

df=df.reset_index(drop=True)

Now:

print(df)

Is:

   A  B
0  1  1
1  1  2
2  2  1
3  2  2

我有另一个好方法来解决这个问题当你有不止一列要爆炸的时候。

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]], 'C':[[1,2,3],[1,2,3]]})

print(df)
   A       B          C
0  1  [1, 2]  [1, 2, 3]
1  2  [1, 2]  [1, 2, 3]

我想爆炸B和C列,首先爆炸B,第二爆炸C,然后从原来的df中去掉B和C。之后,我将在3个dfs上做一个索引连接。

explode_b = df.explode('B')['B']
explode_c = df.explode('C')['C']
df = df.drop(['B', 'C'], axis=1)
df = df.join([explode_b, explode_c])

我的5美分:

df[['B', 'B2']] = pd.DataFrame(df['B'].values.tolist())

df[['A', 'B']].append(df[['A', 'B2']].rename(columns={'B2': 'B'}),
                      ignore_index=True)

还有5个

df[['B1', 'B2']] = pd.DataFrame([*df['B']]) # if values.tolist() is too boring

(pd.wide_to_long(df.drop('B', 1), 'B', 'A', '')
 .reset_index(level=1, drop=True)
 .reset_index())

两者的结果是一样的

   A  B
0  1  1
1  2  1
2  1  2
3  2  2