【问题标题】:pd.json_normalize() gives “str object has no attribute 'values'"pd.json_normalize() 给出“str object has no attribute 'values'”
【发布时间】:2021-06-24 07:14:39
【问题描述】:

我手动创建了一个DataFrame:

import pandas as pd
df_articles1 = pd.DataFrame({'Id'   : [4,5,8,9],
                            'Class':[
                                        {'encourage': 1, 'contacting': 1},
                                        {'cardinality': 16, 'subClassOf': 3},
                                        {'get-13.5.1': 1},
                                        {'cardinality': 12, 'encourage': 1}
                                    ]
                            }) 

我将其导出为一个csv文件,然后拆分后导入:

df_articles1.to_csv(f"""{path}articles_split.csv""", index = False, sep=";")

我可以用pd.json_normalize()拆分它:

df_articles1 = pd.json_normalize(df_articles1['Class'])

我将其 csv 文件导入 DataFrame:

df_articles2 = pd.read_csv(f"""{path}articles_split.csv""", sep=";") 

但这失败了:

AttributeError: 'str' 对象没有属性 'values' pd.json_normalize(df_articles2['Class'])

【问题讨论】:

  • 那是因为当您通过to_csv() 保存时,您的 class 列中的数据存储为string 而不是dictionary/json
  • df_articles1.dtypes 为 Class 列返回“object”类型。它应该返回字符串?
  • 我无法重现这个。您发布的代码运行没有错误。

标签: python json pandas dataframe


【解决方案1】:

虽然接受的答案有效,但 using eval is bad practice.

要解析 看起来 像 JSON/dict 的字符串列,请使用以下选项之一(如果可能,最后一个是最好的)。


ast.literal_eval(更好)

import ast

objects = df2['Class'].apply(ast.literal_eval)
normed = pd.json_normalize(objects)
df2[['Id']].join(normed)

#    Id  encourage  contacting  cardinality  subClassOf  get-13.5.1
# 0   4        1.0         1.0          NaN         NaN         NaN
# 1   5        NaN         NaN         16.0         3.0         NaN
# 2   8        NaN         NaN          NaN         NaN         1.0
# 3   9        1.0         NaN         12.0         NaN         NaN

json.loads(更好)

import json

objects = df2['Class'].apply(json.loads)
normed = pd.json_normalize(objects)
df2[['Id']].join(normed)

#    encourage  contacting  cardinality  subClassOf  get-13.5.1
# 0        1.0         1.0          NaN         NaN         NaN
# 1        NaN         NaN         16.0         3.0         NaN
# 2        NaN         NaN          NaN         NaN         1.0
# 3        1.0         NaN         12.0         NaN         NaN

如果字符串是单引号,在应用json.loads之前使用str.replace将它们转换为双引号(因此是有效的JSON):

objects = df2['Class'].str.replace("'", '"').apply(json.loads)
normed = pd.json_normalize(objects)
df2[['Id']].join(normed)

pd.json_normalize 之前 pd.to_csv(推荐)

如果可能,当您最初保存到 CSV 时,只需保存 规范化 JSON(不是原始 JSON 对象):

df1 = df1[['Id']].join(pd.json_normalize(df1['Class']))
df1.to_csv('df1_normalized.csv', index=False, sep=';')

# Id;encourage;contacting;cardinality;subClassOf;get-13.5.1
# 4;1.0;1.0;;;
# 5;;;16.0;3.0;
# 8;;;;;1.0
# 9;1.0;;12.0;;

这是一个更自然的 CSV 工作流程(而不是存储/加载对象 blob):

df2 = pd.read_csv('df1_normalized.csv', sep=';')

#    Id  encourage  contacting  cardinality  subClassOf  get-13.5.1
# 0   4        1.0         1.0          NaN         NaN         NaN
# 1   5        NaN         NaN         16.0         3.0         NaN
# 2   8        NaN         NaN          NaN         NaN         1.0
# 3   9        1.0         NaN         12.0         NaN         NaN

【讨论】:

    【解决方案2】:

    那是因为当您通过to_csv() 保存时,'Class' 列中的数据存储为string 而不是dictionary/json,因此在加载保存的数据后:

    df_articles2 = pd.read_csv(f"""{path}articles_split.csv""", sep=";") 
    

    然后使用eval() 方法和apply() 方法使其恢复原状:-

    df_articles2['Class']=df_articles2['Class'].apply(lambda x:eval(x))
    

    最后:

    resultdf=pd.json_normalize(df_articles2['Class'])
    

    现在,如果您打印 resultdf,您将获得所需的输出

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-26
      • 1970-01-01
      • 2020-12-29
      • 2017-05-10
      • 1970-01-01
      • 2021-07-25
      • 2015-09-26
      • 1970-01-01
      相关资源
      最近更新 更多