【问题标题】:unlist list of dictionaries in dataframe pandas取消列出数据框熊猫中的字典列表
【发布时间】:2019-05-07 07:15:53
【问题描述】:

我当前的 DataFrame 是这样的:

Index  Animal                                                   AnimalClassId
0      [{animalid:1,color:red,name:cat},{animalid:2,color:blue,name:cat2}]  1
1      [{animalid:3,color:pink,name:pig}]                                   2

所以第一列动物是每行的字典列表。每个 Animal 行都有不同长度的列表。

我的理想输出是:

Index  Animal                           AnimalClassId
0      {animalid:1,color:red,name:cat}       1
1      {animalid:2,color:blue,name:cat2}     1
2      {animalid:3,color:pink,name:pig}      2

此外,这个数据集非常大(超过 100000 行),所以我试图避免循环遍历每一行。有什么快速实施的好方法吗?如有任何建议,我将不胜感激!

【问题讨论】:

  • 您为什么不将您的字典取消嵌套到列中?这当然是您面临性能问题的原因:Pandas 系列不是为保存字典而设计的。我建议您将“理想输出”更改为 more 理想。

标签: python pandas list numpy dataframe


【解决方案1】:

你可以这样做:

ideal_df = df.set_index(["AnimalClassId"])["Animal"]\
  .apply(pd.Series)\
  .stack()\
  .reset_index(level=1, drop=True)\
  .reset_index()

ideal_df.columns = ["AnimalClassId", "Animal"]

(请注意,您可以将其全部放在一行中,也可以将其分成单独的行)

示例:

输入(您的示例):

df = pd.DataFrame({
    "Animal": [
        [{"animalid":1,"color":"red","name":"cat"}, {"animalid":2,"color":"blue","name":"cat2"}],
        [{"animalid":3,"color":"pink","name":"pig"}]
    ], 
    "AnimalClassId": [1, 2]
})

print(df)
                                              Animal  AnimalClassId
0  [{'animalid': 1, 'color': 'red', 'name': 'cat'...              1
1  [{'animalid': 3, 'color': 'pink', 'name': 'pig'}]              2

输出:

print(ideal_df)

   AnimalClassId                                            Animal
0              1    {'animalid': 1, 'color': 'red', 'name': 'cat'}
1              1  {'animalid': 2, 'color': 'blue', 'name': 'cat2'}
2              2   {'animalid': 3, 'color': 'pink', 'name': 'pig'}

如果您的列不仅仅是“AnimalClassId”,则需要将这些列包含在传递给set_index 的列表中,并将传递给reset_indexlevel 参数每增加一列就增加1。例如,如果您有“AnimalHabitat”列,则需要set_index(["AnimalClassId", "AnimalHabitat"])reset_index(level=2, drop=True)

这仍然需要在幕后循环您的数据。由于“动物”列中的数据不统一(不同长度的列表),我怀疑是否有办法以矢量化方式扩展每个元素,但这会解决问题。

【讨论】:

  • 由于某种原因,您提供的代码不起作用。我认为“pd.Series”部分应该扩展列表中的每个项目?对我来说,我的 df 仍然保持不变。有什么线索吗?
  • @YixianWang 尝试按顺序应用每个方法,而不是一次全部应用,看看是否有问题。至少应该发生一些事情,我认为您的 df 不可能在应用所有这些方法的情况下保持不变。
  • @YixianWang 你用的是df还是ideal_df
【解决方案2】:

您必须重新构建它。仔细构建每一列很重要。 一个简单的方法:

def refactor(df):
    animals=[]
    for list in df.Animal : animals.extend(list) # for O(n) operation
    animalclassids=[ id for nb,id in zip(df.Animal.apply(len),df.AnimalClassId)\ 
                     for k in range(nb)]   
    df2= pd.DataFrame({'Animal':animals, 'AnimalClassId':animalclassids})
    return df2

col 1 的循环避免 df.Animal.sum() 这似乎是 O(n²)。

>>> refactor(df)
                                             Animal  AnimalClassId
0    {'animalid': 1, 'color': 'red', 'name': 'cat'}              1
1  {'animalid': 2, 'color': 'blue', 'name': 'cat2'}              1
2   {'animalid': 3, 'color': 'pink', 'name': 'pig'}              2

>>> df2=pd.concat((df,)*50000)

>>> len(df2)
100000

>>> %time res=refactor(df2)
Wall time: 550 ms

【讨论】:

    【解决方案3】:

    不要使用一系列字典

    Pandas 代表“面板数据”,当每个系列代表不同的字段时效果最佳。因此,您可以扩展数据框,然后取消嵌套字典:

    # expand dataframe
    df = pd.DataFrame({'Animal': np.concatenate(df['Animal']),
                       'AnimalClassId': np.repeat(df['AnimalClassId'],
                                                  df['Animal'].str.len())})
    
    # un-nested dictionaries into series
    df = df.join(pd.DataFrame(df.pop('Animal').values.tolist()))
    
    print(df)
    
       AnimalClassId  animalid color  name
    0              1         1   red   cat
    0              1         1   red   cat
    1              2         2  blue  cat2
    

    此方法的优点是生成的数据帧index 为每一行保留原始数据帧的索引。

    【讨论】:

      猜你喜欢
      • 2020-07-22
      • 2015-06-02
      • 2019-08-24
      • 2022-01-23
      • 2017-06-16
      • 2021-12-22
      • 2020-08-14
      相关资源
      最近更新 更多