当前位置: 首页 > 知识库问答 >
问题:

如何在熊猫数据库中打开(爆炸)一列

羊舌航
2023-03-14
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

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

很好的问题和答案,但只处理一列和列表(在我的答案中,自定义函数将适用于多列,而且接受的答案是使用最耗时的apply,这是不建议的,检查更多信息,我什么时候应该在我的代码中使用pandas apply()?)

共有1个答案

慕承允
2023-03-14

我知道ObjectcolumnsType使数据很难用Pandas函数进行转换。当我收到这样的数据时,我想到的第一件事是‘压平’或解开列。

对于这类问题,我使用pandasPython函数。如果您担心上述解决方案的速度,请查看user3483203的答案,因为它使用的是numpy,而且大多数情况下numpy更快。如果速度问题,我推荐cpythonnumba

方法0[pandas>=0.25]
从pandas0.25开始,如果只需要分解一列,可以使用pandas.dataframe.explode函数:

df.explode('B')

       A  B
    0  1  1
    1  1  2
    0  2  1
    1  2  2
df = pd.DataFrame({'A': [1, 2, 3, 4],'B': [[1, 2], [1, 2], [], np.nan]})
df.B = df.B.fillna({i: [] for i in df.index})  # replace NaN with []
df.explode('B')

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

方法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构造函数,重新创建您的dataframe(擅长性能,不擅长多列)

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之外,我们还有一个。如果我们仍然使用上面的方法(方法2),我们很难逐个重新创建列。

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
s.join(df.drop('B',1),how='left').reindex(columns=df.columns)
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]

方法4
使用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
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
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
def unnesting(df, explode, axis):
    if axis==1:
        df1 = pd.concat([df[x].explode() for x in explode], axis=1)
        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')
 类似资料:
  • 问题内容: 我有一个表名消息。我需要获取一个列名,其中 receiver_id = 4, 但我总是得到空输出。 屏幕截图上方有3行。第二行和第三行与其他ID一起存在,我需要对其进行分解并显示第二行和第三行记录。 如何编写MySQL查询? 问题答案: 存储逗号分隔值确实是一个糟糕的设计,您应该 首先将接收方的所有关联存储在联结表中,如果您无法更改架构,则可以针对当前情况在逗号分隔列表中搜索值

  • 我有一个数据框,其中一列文本字符串包含逗号分隔的值。我想分割每个CSV字段,并为每个条目创建一个新行(假设CSV是干净的,只需要在“,”上分割)。例如,应该变成: 到目前为止,我已经尝试了各种简单的函数,但是方法在轴上使用时似乎只接受一行作为返回值,并且我无法让工作。任何建议都将不胜感激! 示例数据: 我知道这是行不通的,因为我们失去了DataFrame元数据通过通过Numpy,但它应该给你一个感

  • 问题内容: 我想从包含单词列表的DataFrame转换为每个单词都在其自己行中的DataFrame。 如何在DataFrame中的列上爆炸? 这是我尝试的一些示例,您可以在其中取消注释每个代码行并获取以下注释中列出的错误。我在带有Spark 1.6.1的Python 2.7中使用PySpark。 请指教 问题答案: 和是SQL函数。两者都在SQL上运行。将Java正则表达式作为第二个参数。如果要在

  • 问题内容: 我有一个包含JSON对象的表。每个JSON对象在方括号中均包含一个数组,并用逗号分隔。 如何使用SQL访问方括号数组中的任何元素,例如“ Matt”? 我在Hadoop上使用“ Hive”。如果您知道如何在SQL中执行此操作,那很好:) 问题答案: 您可以在Hive中执行以下操作: 首先,您需要一个JSON SerDe(Serializer / Deserializer)。我见过的最实

  • 我有一个dataframe,从中删除了一些行。因此,我得到了一个dataframe,其中的索引类似于:,我希望将其重置为。我怎么做?

  • 问题内容: 我遇到了一个看似简单的问题:在熊猫数据框中删除唯一的行。基本上与的相反。 假设这是我的数据: 当A和B唯一时,我想删除行,即我只保留行1和2。 我尝试了以下方法: 但是我只能得到第2行,因为唯一性是0、1和3! 问题答案: 选择所有重复行的解决方案: 您可以使用子集和参数来选择所有重复项: 解决方案: 对所有唯一行进行了一些修改的解决方案: