将Pandas数据框内的JSON数据转换为数据框本身的最佳方法

时间:2019-05-13 06:28:50

标签: python json pandas dataframe

我有一个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使其更快。

编辑2: pd.DataFrame(df["js"].apply(json.loads).tolist())花了25.2 ms ± 512 µs,所以我猜想有一个赢家。

3 个答案:

答案 0 :(得分:3)

使用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

OR:

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']])

答案 1 :(得分:2)

在将字符串转换为dict后,我将调用dataframe构造函数(我认为这样做会更快):

  constructor(private db: AngularFirestore) {
    this.usersCollection = this.db.collection<User>('Users');

    this.users = this.usersCollection.snapshotChanges().pipe(
      map(actions => {
        return actions.map(a => {
          const data = a.payload.doc.data();
          const id = a.payload.doc.id;
          return { id, ...data };
        });
      })
    );
  }

或者:


  getUser(id) { 
    this.usersCollection = this.db.collection<User>('Users', ref => ref.where('userId', '==', id));
    this.users = this.usersCollection.snapshotChanges().pipe(
      map(actions => {
        return actions.map(a => {
          const data = a.payload.doc.data();
          const id = a.payload.doc.id;
          return { id, ...data };
        });
      })
    );
    return this.users;
  }

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

答案 2 :(得分:1)

您可以使用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