在数据框熊猫中不列出字典列表

时间:2018-12-05 16:49:28

标签: python pandas list numpy dataframe

我当前的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

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

我的理想输出是:

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行),因此我试图避免循环遍历每一行。有什么好的方法可以快速实施吗?任何建议,我将不胜感激!

3 个答案:

答案 0 :(得分:0)

您可以执行以下操作:

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的列表中包括这些列,并将传递给level的{​​{1}}参数增加1每增加一列。例如,如果您有“动物栖息地”列,则需要reset_indexset_index(["AnimalClassId", "AnimalHabitat"])

这仍然需要在后台遍历您的数据。由于“动物”列中的数据不是统一的(列表的长度是可变的),我怀疑是否存在一种以矢量化方式扩展每个元素的方法,但这可以解决问题。

答案 1 :(得分:0)

您必须对其进行重建。仔细构建每一列很重要。  一种简单的方法:

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

答案 2 :(得分:0)

不要使用一系列字典

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保留每行原始数据帧的索引。