unlist список словарей в пандах данных

1

Мой текущий 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+ строки), поэтому я пытаюсь избежать цикла через каждую строку. Какие-нибудь хорошие методы для быстрой реализации? Буду признателен за любые предложения!

  • 2
    Почему бы вам не раскрутить словарь в столбцы? Конечно, это причина, по которой вы сталкиваетесь с проблемами производительности: серии Pandas не предназначены для хранения словарей. Я советую вам изменить ваш «идеальный результат» на что-то более идеальное.
Теги:
pandas
dataframe
numpy
list

3 ответа

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
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 переданный в reset_index на 1 для каждого дополнительного столбца. Например, если у вас есть столбец "AnimalHabitat", вам понадобится set_index(["AnimalClassId", "AnimalHabitat"]) и reset_index(level=2, drop=True).

Это все равно придется перебирать ваши данные за кулисами. Поскольку данные в столбце "Животные" не являются однородными (списки переменной длины), я сомневаюсь, что есть способ расширить каждый элемент в векторе, но это будет делать трюк.

  • 0
    по какой-то причине предоставленный вами код не работает. Я думаю, что часть "pd.Series" должна расширять каждый элемент в списке? Для меня мой DF все еще остается прежним. Есть какие-нибудь подсказки по этому поводу?
  • 0
    @YixianWang попробуйте применить каждый метод последовательно, а не все сразу, и посмотрите, не кажется ли это чем-то неправильным По крайней мере, что-то должно произойти, я не думаю, что ваш df может остаться прежним со всеми этими методами.
Показать ещё 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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню