Как быстро создать двухмерный массив numpy из элементов json?

#python #json #numpy

#python #json #тупой

Вопрос:

У меня есть вложенные данные json, которые похожи на следующие:

 [{'game':'001', 'animals': [{'name':'Dog', 'colour':'Red'}, {'name':'Horse', 'age':'6'},{'name':'Ostrich', 'location':'Africa'}]},{'game':'002', 'animals': [{'name':'Cat', 'colour':'Green'}, {'name':'Bison', 'location':'North America'},{'name':'Parrot', 'location':'Southeast Asia'}]}]
 

Моя цель — создать запись массива индикаторов для каждого животного (содержащегося в ‘name’), соответствующую элементам в переменной «animal_list»:

 animal_list = ['Bison', 'Cat', 'Dog', 'Elephants', 'Horse', 'Ostrich', 'Parrot']
 

Таким образом, желаемая структура будет напоминать (выраженную в формате csv…но это иллюстративно только потому, что я ищу позиционный массив numpy):

 Game, Bison, Cat, Dog, Elephants, Horse, Ostrich, Parrot
"001",0,0,1,0,1,1,0
"002",1,1,0,0,0,0,1
 

Я традиционно формировал это с помощью «двойного цикла» — сначала для «игровых» предметов; затем следует внутренний цикл, который просматривает «именные» предметы. Проблема в том, что у меня длинный список json, и на его выполнение уходит несколько часов.

Спасибо за вашу помощь!

Комментарии:

1. Пожалуйста, предоставьте код для вашего текущего подхода.

2. он все еще кажется недействительным

3. Почему бы не использовать pandas?

4. Если вы покажете нам свой традиционный метод, нам будет легче предложить улучшения. Это также облегчает тестирование.

5. json является строкой; loads создает словарь. Существует только 2 способа доступа к элементам словаря — путем индексации ключей или через items списки. numpy у него нет магии, чтобы сделать что-то из этого быстрее.

Ответ №1:

Ниже приведена версия таблицы для pandas.

Вы всегда можете обратиться к ndarray as df.values

 import numpy as np
import pandas as pd

data = [{'game': '001', 'animals': [{'name':'Dog', 'colour':'Red'}, {'name':'Horse', 'age':'6'},{'name':'Ostrich', 'location':'Africa'}]},
        {'game': '002', 'animals': [{'name':'Cat', 'colour':'Green'}, {'name':'Bison', 'location':'North America'},{'name':'Parrot', 'location':'Southeast Asia'}]}]
animal_list = ['Bison', 'Cat', 'Dog', 'Elephants', 'Horse', 'Ostrich', 'Parrot']

games = [d['game'] for d in data]

df = pd.DataFrame(np.zeros((len(games), len(animal_list))),
                  index=games, columns=animal_list)

for ix, g in enumerate(games):
    a = [a['name'] for a in data[ix]['animals']]
    df.loc[g, a] = 1

print(df)


       Bison  Cat  Dog  Elephants  Horse  Ostrich  Parrot
001    0.0  0.0  1.0        0.0    1.0      1.0     0.0
002    1.0  1.0  0.0        0.0    0.0      0.0     1.0
 

Комментарии:

1. Большое спасибо за это. Намного элегантнее, чем цикл, который я использую. Вопрос — у меня сложилось впечатление, что поиск по фреймам данных происходит медленно. Может быть быстрее использовать массив numpy и добавлять?

2. в принципе, вы правы. но в вашем случае, поскольку исходные данные помечены строками, а не позициями, вам придется вручную преобразовать метки в индексы. Это, вероятно, будет стоить вам дороже и будет менее элегантно.