【问题标题】:Best way to transform JSON data within a Pandas dataframe into a dataframe itself将 Pandas 数据框中的 JSON 数据转换为数据框本身的最佳方法
【发布时间】:2023-04-05 01:51:01
【问题描述】:

我有一个 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-objects 变成他们自己的数据框:

  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:

感谢您的回答。

我已经在我自己的方法采用158 ms ± 4.01 ms 的真实数据上使用ast.literal_eval 对三种建议的方法进行计时:

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 所以我猜我们有一个赢家。

【问题讨论】:

    标签: python json pandas dataframe


    【解决方案1】:

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

    或者:

    import json
    df = pd.DataFrame([json.loads(i) for i in df['js']])
    

    【讨论】:

    • 谢谢,但这种方法比我的慢得多,请参阅编辑。
    • @Khris 检查我的新方法。
    • 第二个更快,第三个与@anky_91 的to_list-approach 一样快。
    【解决方案2】:

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

    【讨论】:

    • 谢谢,这种方法几乎和我的一样快,但遗憾的是仍然慢。
    【解决方案3】:

    我会在将字符串转换为 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
    

    【讨论】:

    • 谢谢,但这种方法比我的慢得多,请参阅编辑。
    • @Khris pd.DataFrame(df["js"].apply(json.loads).tolist()) 怎么样?
    • 25.2 ms ± 512 µs,这就是我要找的。​​span>
    猜你喜欢
    • 2019-05-14
    • 2019-07-01
    • 2021-12-13
    • 2014-12-27
    • 1970-01-01
    • 2020-06-17
    • 2020-10-05
    • 2019-11-24
    • 1970-01-01
    相关资源
    最近更新 更多