Python-如何在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]

我的预期输出是:

   A  B

0 1 1

1 1 2

3 2 1

4 2 2

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

回答:

作为同时使用Rpython,我已经多次看到这种类型的问题。

R中,它们具有tidyr名为的包中的内置函数unnest。但是Python(pandas)中没有针对此类问题的内置函数。

我知道objecttype总是使数据难以通过pandas'函数进行转换。当我收到这样的数据时,想到的第一件事就是“弄平”或取消嵌套列。

我正在使用pandaspython函数来解决此类问题。如果你担心上述解决方案的速度,请检查user3483203的答案,因为他正在使用numpy并且大多数时候numpy速度更快。我建议Cpython,并numba如果速度在你的情况很重要。

从pandas 0.25开始,如果只需要爆炸一列,则可以使用以下explode函数:

df.explode('B')

A B

0 1 1

1 1 2

0 2 1

1 2 2

方法1

apply + pd.Series(易于理解,但不建议使用性能。)

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

方法2与构造函数一起

使用,重新创建你的数据框(擅长性能,不擅长多列)repeatDataFrame

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

例如,方法2.1除了A之外,还有A.1 ..... An如果仍然使用上面的method(方法2),则很难一一重建列。

解决方案:joinmergeindex后“UNNEST”单列

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

如果需要与以前完全相同的列顺序,请reindex在末尾添加。

s.join(df.drop('B',1),how='left').reindex(columns=df.columns)

重新创建list

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

如果超过两列,请使用

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]

使用reindexloc

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))

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

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

使用方法6numpy:

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

使用基本函数itertools cycle和chain:Pure python解决方案只是为了好玩

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

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]

自我定义功能:

def unnesting(df, explode):

idx = df.index.repeat(df[explode[0]].str.len())

df1 = pd.concat([

pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)

df1.index = idx

return df1.join(df.drop(explode, 1), how='left')

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

Out[609]:

B C A

0 1 1 1

0 2 2 1

1 3 3 2

1 4 4 2

列式嵌套

以上所有方法都在谈论垂直嵌套和爆炸,如果你确实需要水平扩展列表,请使用pd.DataFrame构造函数检查

df.join(pd.DataFrame(df.B.tolist(),index=df.index).add_prefix('B_'))

Out[33]:

A B C B_0 B_1

0 1 [1, 2] [1, 2] 1 2

1 2 [3, 4] [3, 4] 3 4

更新功能

def unnesting(df, explode, axis):

if axis==1:

idx = df.index.repeat(df[explode[0]].str.len())

df1 = pd.concat([

pd.DataFrame({x: np.concatenate(df[x].values)}) for x in explode], axis=1)

df1.index = idx

return df1.join(df.drop(explode, 1), how='left')

else :

df1 = pd.concat([

pd.DataFrame(df[x].tolist(), index=df.index).add_prefix(x) for x in explode], axis=1)

return df1.join(df.drop(explode, 1), how='left')

测试输出

unnesting(df, ['B','C'], axis=0)

Out[36]:

B0 B1 C0 C1 A

0 1 2 1 2 1

1 3 4 3 4 2

以上是 Python-如何在pandas数据帧中取消(分解)列? 的全部内容, 来源链接: utcz.com/qa/419006.html

回到顶部