Pandas DataFrame превращает список столбцов jsons в информативную строку, согласно «id» - PullRequest
0 голосов
/ 25 ноября 2018

Рассмотрим следующий фрейм данных:

import pandas as pd

df = pd.DataFrame({'id': [1, 2, 3],
               'json_col': [ [{'aa' : 1, 'ab' : 1}, {'aa' : 3, 'ab' : 2, 'ac': 6}],
                             [{'aa' : 1, 'ab' : 2, 'ac': 1}, {'aa' : 5}],
                             [{'aa': 3, 'ac': 2}] ]})
df
Out[134]: 
   id                                           json_col
0   1  [{'aa': 1, 'ab': 1}, {'aa': 3, 'ab': 2, 'ac': 6}]
1   2           [{'aa': 1, 'ab': 2, 'ac': 1}, {'aa': 5}]
2   3                               [{'aa': 3, 'ac': 2}]

Мы можем видеть, что у нас есть список jsons для каждого идентификатора.

Я бы хотел, для каждого 'id' и для каждогосоответствующий JSON в своем списке, чтобы иметь 'row' в DataFrame.Таким образом, следующее DataFrame будет выглядеть так:

   id  aa   ab   ac
0   1   1  1.0  NaN
1   1   3  2.0  6.0
2   2   1  2.0  1.0
3   2   5  NaN  NaN
4   3   3  NaN  2.0

Мы можем видеть, что id '1' имеет 2 соответствующих jsons в своем списке, и поэтому он получает 2 строки в новом DataFrame

Есть ли питонский способ сделать это, используя функции panda, numpy или json ?


Добавление времени выполнения решений

setup = """
import pandas as pd
df = pd.DataFrame({'id': [1, 2, 3],
               'json_col': [ [{'aa' : 1, 'ab' : 1}, {'aa' : 3, 'ab' : 2, 'ac': 6}],
                             [{'aa' : 1, 'ab' : 2, 'ac': 1}, {'aa' : 5}],
                             [{'aa': 3, 'ac': 2}] ]})
"""

s1 = """
df = pd.concat(
       [pd.DataFrame(j, index=[i]*len(j)) for i, j in enumerate(df['json_col'], 1)],
       sort=False
     )                             
"""

s2 = """
recs = df.apply(lambda x: [{**{'id': x.id}, **d} for d in x.json_col], axis=1).sum()
df2 = pd.DataFrame.from_records(recs)
"""

%timeit(s1, setup)
52.3 ns ± 2.6 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%timeit(s2, setup)
50.6 ns ± 3.28 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Вот один быстрый способ - преобразовать все списки словарей json_col в DataFrame и объединить их вместе, а также несколько настроек для создания столбца id:

In [51]: df = pd.concat(
           [pd.DataFrame(j, index=[i]*len(j)) for i, j in enumerate(json_col, 1)],
           sort=False
         )

In [52]: df.index.name = 'id'

In [53]: df.reset_index()
Out[53]: 
   id  aa   ab   ac
0   1   1  1.0  NaN
1   1   3  2.0  6.0
2   2   1  2.0  1.0
3   2   5  NaN  NaN
4   3   3  NaN  2.0
0 голосов
/ 25 ноября 2018

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

recs = df.apply(lambda x: [{**{'id': x.id}, **d} for d in x.json_col], axis=1).sum()
df2 = pd.DataFrame.from_records(recs)
# outputs:
   aa   ab   ac  id
0   1  1.0  NaN   1
1   3  2.0  6.0   1
2   1  2.0  1.0   2
3   5  NaN  NaN   2
4   3  NaN  2.0   3

Как это работает:

  1. Примененная лямбда-выражение создает новый словарь, объединяя содержимое {id: x.id} вкаждый словарь в списке словарей в x.json_col (где x - строка).

  2. Затем он суммируется.Поскольку суммирование списков списка элементов объединяет их в большой список элементов, recs имеет следующую форму:

    [{'id': 1, 'aa': 1, 'ab': 1},
     {'id': 1, 'aa': 3, 'ab': 2, 'ac': 6},
     {'id': 2, 'aa': 1, 'ab': 2, 'ac': 1},
     {'id': 2, 'aa': 5},
     {'id': 3, 'aa': 3, 'ac': 2}]
    
  3. Новый фрейм данных затем просто создается из записей.

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