unlist список словарей в пандах данных - PullRequest
0 голосов
/ 05 декабря 2018

Мой текущий 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

Кроме того, этот набор данных чрезвычайно большой (более 100 000 строк), поэтому я стараюсь избегать циклического прохождения каждогострока.Какие-нибудь хорошие методы для быстрой реализации?Буду признателен за любые предложения!

Ответы [ 3 ]

0 голосов
/ 05 декабря 2018

Вы должны восстановить его. Важно тщательно построить каждый столбец.Простой способ сделать это:

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

цикл для столбца 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
0 голосов
/ 05 декабря 2018

Не используйте серии словарей

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 сохраняют индекс из оригинального фрейма данных для каждогостроки.

0 голосов
/ 05 декабря 2018

Вы можете сделать это с помощью:

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

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

(обратите внимание, что вы можете поместить это все в одну строку или разбить на отдельные строки)

Пример:

input (ваш пример):

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

output:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...