如何在pandas DataFrame中删除(爆炸)列?

WeN*_*Ben 76 python dataframe pandas

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

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[1,2]]})
df
Out[458]: 
   A       B
0  1  [1, 2]
1  2  [1, 2]
Run Code Online (Sandbox Code Playgroud)

我的预期输出是:

   A  B
0  1  1
1  1  2
3  2  1
4  2  2
Run Code Online (Sandbox Code Playgroud)

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


相关问题

pandas:当单元格内容是列表时,为列表中的每个元素创建一行

好的问题和答案,但只处理一列列表(在我的回答中,自我修复功能将适用于多列,也接受的答案是使用最耗时apply,不推荐,检查更多信息我应该什么时候想要在我的代码中使用pandas apply()?)

WeN*_*Ben 112


与既有用户Rpython,我已经看到了这样的问题了几次.


在R,他们从包中的内置函数tidyrunnest.但在Python(pandas)中,这类问题没有内置函数.


我知道objecttype总是使用pandas'函数很难转换数据.当我收到这样的数据时,首先想到的是"压扁"或者不需要列.


方法1 pandas(易于理解,但在性能方面不推荐.)

df.explode('B')

       A  B
    0  1  1
    1  1  2
    0  2  1
    1  2  2
Run Code Online (Sandbox Code Playgroud)

方法2使用pythonnumpy构造,重新创建数据框(善于表现,在多列不好)

df.set_index('A').B.apply(pd.Series).stack().reset_index(level=0).rename(columns={0:'B'})
Out[463]: 
   A  B
0  1  1
1  1  2
0  2  1
1  2  2
Run Code Online (Sandbox Code Playgroud)

方法2.1例如除了A我们有A.1 ..... An如果我们仍然使用上面的方法(方法2),我们很难一个接一个地重新创建列.

解决方案:numpyCpythonnumba后"UNNEST"单列

df=pd.DataFrame({'A':df.A.repeat(df.B.str.len()),'B':np.concatenate(df.B.values)})
df
Out[465]: 
   A  B
0  1  1
0  1  2
1  2  1
1  2  2
Run Code Online (Sandbox Code Playgroud)

如果您需要与之前完全相同的列顺序,请explode在最后添加.

s=pd.DataFrame({'B':np.concatenate(df.B.values)},index=df.index.repeat(df.B.str.len()))
s.join(df.drop('B',1),how='left')
Out[477]: 
   B  A
0  1  1
0  2  1
1  1  2
1  2  2
Run Code Online (Sandbox Code Playgroud)

方法3 重新创建apply + pd.Series

s.join(df.drop('B',1),how='left').reindex(columns=df.columns)
Run Code Online (Sandbox Code Playgroud)

如果超过两列

pd.DataFrame([[x] + [z] for x, y in df.values for z in y],columns=df.columns)
Out[488]: 
   A  B
0  1  1
1  1  2
2  2  1
3  2  2
Run Code Online (Sandbox Code Playgroud)

方法4使用repeatDataFrame

s=pd.DataFrame([[x] + [z] for x, y in zip(df.index,df.B) for z in y])
s.merge(df,left_on=0,right_index=True)
Out[491]: 
   0  1  A       B
0  0  1  1  [1, 2]
1  0  2  1  [1, 2]
2  1  1  2  [1, 2]
3  1  2  2  [1, 2]
Run Code Online (Sandbox Code Playgroud)

方法5当列表仅包含唯一值时:

df.reindex(df.index.repeat(df.B.str.len())).assign(B=np.concatenate(df.B.values))
Out[554]: 
   A  B
0  1  1
0  1  2
1  2  1
1  2  2

#df.loc[df.index.repeat(df.B.str.len())].assign(B=np.concatenate(df.B.values))
Run Code Online (Sandbox Code Playgroud)

方法6采用join高性能:

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]]})
from collections import ChainMap
d = dict(ChainMap(*map(dict.fromkeys, df['B'], df['A'])))
pd.DataFrame(list(d.items()),columns=df.columns[::-1])
Out[574]: 
   B  A
0  1  1
1  2  1
2  3  2
3  4  2
Run Code Online (Sandbox Code Playgroud)

方法7 :使用基本功能merge indexreindex:纯粹的python解决方案只是为了好玩

newvalues=np.dstack((np.repeat(df.A.values,list(map(len,df.B.values))),np.concatenate(df.B.values)))
pd.DataFrame(data=newvalues[0],columns=df.columns)
   A  B
0  1  1
1  1  2
2  2  1
3  2  2
Run Code Online (Sandbox Code Playgroud)

特殊情况(两列式对象)

from itertools import cycle,chain
l=df.values.tolist()
l1=[list(zip([x[0]], cycle(x[1])) if len([x[0]]) > len(x[1]) else list(zip(cycle([x[0]]), x[1]))) for x in l]
pd.DataFrame(list(chain.from_iterable(l1)),columns=df.columns)
   A  B
0  1  1
1  1  2
2  2  1
3  2  2
Run Code Online (Sandbox Code Playgroud)

自我防御功能

df=pd.DataFrame({'A':[1,2],'B':[[1,2],[3,4]],'C':[[1,2],[3,4]]})
df
Out[592]: 
   A       B       C
0  1  [1, 2]  [1, 2]
1  2  [3, 4]  [3, 4]
Run Code Online (Sandbox Code Playgroud)

摘要:

我正在使用listreindex运行这类问题.如果您担心上述解决方案的速度,请检查user3483203的答案,因为他正在使用loc并且大部分时间numpy都更快.我建议itertools,cycle如果速度对你的情况很重要.

  • 从版本 1.3.0 开始,我们可以一次explode()多个列。 (12认同)

use*_*203 34

选项1

如果另一列中的所有子列表长度相同,则numpy可以是以下有效选项:

vals = np.array(df.B.values.tolist())    
a = np.repeat(df.A, vals.shape[1])

pd.DataFrame(np.column_stack((a, vals.ravel())), columns=df.columns)
Run Code Online (Sandbox Code Playgroud)

   A  B
0  1  1
1  1  2
2  2  1
3  2  2
Run Code Online (Sandbox Code Playgroud)

选项2

如果子列表具有不同的长度,则需要执行其他步骤:

vals = df.B.values.tolist()
rs = [len(r) for r in vals]    
a = np.repeat(df.A, rs)

pd.DataFrame(np.column_stack((a, np.concatenate(vals))), columns=df.columns)
Run Code Online (Sandbox Code Playgroud)

   A  B
0  1  1
1  1  2
2  2  1
3  2  2
Run Code Online (Sandbox Code Playgroud)

选项3

我试着将其概括为一个用于压扁N列和瓷砖M列的工作,稍后我会努力提高它的效率:

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']})
Run Code Online (Sandbox Code Playgroud)

   A          B          C  D
0  1     [1, 2]  [1, 2, 3]  A
1  2  [1, 2, 3]     [1, 2]  B
2  3        [1]     [1, 2]  C
Run Code Online (Sandbox Code Playgroud)

def unnest(df, tile, explode):
    vals = df[explode].sum(1)
    rs = [len(r) for r in vals]
    a = np.repeat(df[tile].values, rs, axis=0)
    b = np.concatenate(vals.values)
    d = np.column_stack((a, b))
    return pd.DataFrame(d, columns = tile +  ['_'.join(explode)])

unnest(df, ['A', 'D'], ['B', 'C'])
Run Code Online (Sandbox Code Playgroud)

    A  D B_C
0   1  A   1
1   1  A   2
2   1  A   1
3   1  A   2
4   1  A   3
5   2  B   1
6   2  B   2
7   2  B   3
8   2  B   1
9   2  B   2
10  3  C   1
11  3  C   1
12  3  C   2
Run Code Online (Sandbox Code Playgroud)

功能

def wen1(df):
    return df.set_index('A').B.apply(pd.Series).stack().reset_index(level=0).rename(columns={0: 'B'})

def wen2(df):
    return pd.DataFrame({'A':df.A.repeat(df.B.str.len()),'B':np.concatenate(df.B.values)})

def wen3(df):
    s = pd.DataFrame({'B': np.concatenate(df.B.values)}, index=df.index.repeat(df.B.str.len()))
    return s.join(df.drop('B', 1), how='left')

def wen4(df):
    return pd.DataFrame([[x] + [z] for x, y in df.values for z in y],columns=df.columns)

def chris1(df):
    vals = np.array(df.B.values.tolist())
    a = np.repeat(df.A, vals.shape[1])
    return pd.DataFrame(np.column_stack((a, vals.ravel())), columns=df.columns)

def chris2(df):
    vals = df.B.values.tolist()
    rs = [len(r) for r in vals]
    a = np.repeat(df.A.values, rs)
    return pd.DataFrame(np.column_stack((a, np.concatenate(vals))), columns=df.columns)
Run Code Online (Sandbox Code Playgroud)

计时

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from timeit import timeit

res = pd.DataFrame(
       index=['wen1', 'wen2', 'wen3', 'wen4', 'chris1', 'chris2'],
       columns=[10, 50, 100, 500, 1000, 5000, 10000],
       dtype=float
)

for f in res.index:
    for c in res.columns:
        df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})
        df = pd.concat([df]*c)
        stmt = '{}(df)'.format(f)
        setp = 'from __main__ import df, {}'.format(f)
        res.at[f, c] = timeit(stmt, setp, number=50)

ax = res.div(res.min()).T.plot(loglog=True)
ax.set_xlabel("N")
ax.set_ylabel("time (relative)")
Run Code Online (Sandbox Code Playgroud)

性能

在此输入图像描述

  • 有趣的是,很高兴知道与新的“df.explode”方法的比较。 (5认同)

Dan*_*ejo 9

另一种方法是将meshgrid配方应用于列的行以免除:

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()
Run Code Online (Sandbox Code Playgroud)

产量

   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
Run Code Online (Sandbox Code Playgroud)


joe*_*lom 9

通过添加方法,在pandas 0.25中显着简化了爆炸式列表explode()

df = pd.DataFrame({'A': [1, 2], 'B': [[1, 2], [1, 2]]})
df.explode('B')
Run Code Online (Sandbox Code Playgroud)

出:

   A  B
0  1  1
0  1  2
1  2  1
1  2  2
Run Code Online (Sandbox Code Playgroud)


piR*_*red 5

问题设置

假设有多个具有不同长度对象的列

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

df

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]
Run Code Online (Sandbox Code Playgroud)

当长度相同时,我们很容易假设不同的元素重合并且应该“压缩”在一起。

   A       B          C
0  1  [1, 2]     [1, 2]  # Typical to assume these should be zipped [(1, 1), (2, 2)]
1  2  [3, 4]  [3, 4, 5]
Run Code Online (Sandbox Code Playgroud)

然而,当我们看到不同长度的物体时,假设会受到挑战,我们是否应该“压缩”,如果是这样,我们如何处理其中一个物体的多余部分。 或者,也许我们想要所有对象的乘积。这会很快变大,但可能是我们想要的。

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]  # is this [(3, 3), (4, 4), (None, 5)]?
Run Code Online (Sandbox Code Playgroud)

或者

   A       B          C
0  1  [1, 2]     [1, 2]
1  2  [3, 4]  [3, 4, 5]  # is this [(3, 3), (3, 4), (3, 5), (4, 3), (4, 4), (4, 5)]
Run Code Online (Sandbox Code Playgroud)

功能

这个函数优雅地处理zipproduct基于一个参数并假设zip根据最长对象的长度zip_longest

from itertools import zip_longest, product

def xplode(df, explode, zipped=True):
    method = zip_longest if zipped else product

    rest = {*df} - {*explode}

    zipped = zip(zip(*map(df.get, rest)), zip(*map(df.get, explode)))
    tups = [tup + exploded
     for tup, pre in zipped
     for exploded in method(*pre)]

    return pd.DataFrame(tups, columns=[*rest, *explode])[[*df]]
Run Code Online (Sandbox Code Playgroud)

压缩

xplode(df, ['B', 'C'])

   A    B  C
0  1  1.0  1
1  1  2.0  2
2  2  3.0  3
3  2  4.0  4
4  2  NaN  5
Run Code Online (Sandbox Code Playgroud)

产品

xplode(df, ['B', 'C'], zipped=False)

   A  B  C
0  1  1  1
1  1  1  2
2  1  2  1
3  1  2  2
4  2  3  3
5  2  3  4
6  2  3  5
7  2  4  3
8  2  4  4
9  2  4  5
Run Code Online (Sandbox Code Playgroud)

新设置

稍微改变一下例子

df = pd.DataFrame({
    'A': [1, 2],
    'B': [[1, 2], [3, 4]],
    'C': 'C',
    'D': [[1, 2], [3, 4, 5]],
    'E': [('X', 'Y', 'Z'), ('W',)]
})

df

   A       B  C          D          E
0  1  [1, 2]  C     [1, 2]  (X, Y, Z)
1  2  [3, 4]  C  [3, 4, 5]       (W,)
Run Code Online (Sandbox Code Playgroud)

压缩

xplode(df, ['B', 'D', 'E'])

   A    B  C    D     E
0  1  1.0  C  1.0     X
1  1  2.0  C  2.0     Y
2  1  NaN  C  NaN     Z
3  2  3.0  C  3.0     W
4  2  4.0  C  4.0  None
5  2  NaN  C  5.0  None
Run Code Online (Sandbox Code Playgroud)

产品

xplode(df, ['B', 'D', 'E'], zipped=False)

    A  B  C  D  E
0   1  1  C  1  X
1   1  1  C  1  Y
2   1  1  C  1  Z
3   1  1  C  2  X
4   1  1  C  2  Y
5   1  1  C  2  Z
6   1  2  C  1  X
7   1  2  C  1  Y
8   1  2  C  1  Z
9   1  2  C  2  X
10  1  2  C  2  Y
11  1  2  C  2  Z
12  2  3  C  3  W
13  2  3  C  4  W
14  2  3  C  5  W
15  2  4  C  3  W
16  2  4  C  4  W
17  2  4  C  5  W
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

14160 次

最近记录:

5 年,11 月 前