Лучший способ преобразовать данные JSON внутри фрейма данных Pandas в сам фрейм данных - PullRequest
2 голосов
/ 13 мая 2019

У меня есть фрейм данных Pandas, в котором один столбец содержит не вложенный объект json в каждой строке.

                             js
0  {"k1":"1","k2":"A","k3":"X"}
1  {"k1":"2","k2":"B","k3":"X"}
2  {"k1":"3","k2":"A","k3":"Y"}
3  {"k1":"4","k2":"D","k4":"M"}

Создан так:

import pandas as pd
L0 = ['{"k1":"1","k2":"A","k3":"X"}',
      '{"k1":"2","k2":"B","k3":"X"}',
      '{"k1":"3","k2":"A","k3":"Y"}',
      '{"k1":"4","k2":"D","k4":"M"}']
df = pd.DataFrame({'js':L0})

Я хочу сделать json-объекты в свой собственный фрейм данных:

  k1 k2   k3   k4
0  1  A    X  NaN
1  2  B    X  NaN
2  3  A    Y  NaN
3  4  D  NaN    M

Прямо сейчас единственный известный мне способ - использовать модуль json и df.iterrows():

import json
all_json = []
for _,row in df.iterrows():
    all_json.append(json.loads(row["js"]))
df2 = pd.DataFrame.from_dict(all_json)

Есть ли лучший способчтобы сделать это, в идеале без итерации?

РЕДАКТИРОВАТЬ 1:

Спасибо за ответы.

Я рассчитал три предложенных подхода, используя ast.literal_eval на моих реальных данных мирагде мой собственный подход занимает 158 ms ± 4.01 ms:

df = df.apply(lambda x: ast.literal_eval(x[0]), 1).apply(pd.Series) занимает 640 ms ± 7.8 ms

df['js'].apply(ast.literal_eval).apply(pd.Series) занимает 636 ms ± 19 ms

pd.DataFrame(df.js.apply(ast.literal_eval).tolist()) занимает 180 ms ± 5.11

Как и предполагалось, третий подход - самый быстрый, но, к сожалению, все они медленнее, чем iterrows -подход, в то время как я намеревался избавиться от iterrows, чтобы сделать его быстрее.

EDIT 2: pd.DataFrame(df["js"].apply(json.loads).tolist()) берет 25.2 ms ± 512 µs поэтому у нас есть победитель, я думаю.

Ответы [ 3 ]

3 голосов
/ 13 мая 2019

Используйте ast.literal_eval и применяйте pd.Series как:

import ast
df = df.apply(lambda x: ast.literal_eval(x[0]), 1).apply(pd.Series)

print(df)
  k1 k2   k3   k4
0  1  A    X  NaN
1  2  B    X  NaN
2  3  A    Y  NaN
3  4  D  NaN    M

ИЛИ:

df = pd.DataFrame([ast.literal_eval(i) for i in df['js']])

OR

import json
df = pd.DataFrame([json.loads(i) for i in df['js']])
2 голосов
/ 13 мая 2019

Я бы вызвал конструктор dataframe после преобразования строки в dict ( Я думаю, это будет быстрее ):

import ast
pd.DataFrame(df.js.apply(ast.literal_eval).tolist())

Или:

import json
pd.DataFrame(df["js"].apply(json.loads).tolist())

  k1 k2   k3   k4
0  1  A    X  NaN
1  2  B    X  NaN
2  3  A    Y  NaN
3  4  D  NaN    M
1 голос
/ 13 мая 2019

Вы можете использовать apply(pd.Series):

import ast
print(df['js'].apply(ast.literal_eval).apply(pd.Series))

Выход:

  k1 k2   k3   k4
0  1  A    X  NaN
1  2  B    X  NaN
2  3  A    Y  NaN
3  4  D  NaN    M
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...