pd.json_normalize() 函数报错 "str object has no attribute 'values'"

5

我手动创建了一个数据框:

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' object has no attribute 'values' pd.json_normalize(df_articles2['Class'])


2
那是因为当您使用to_csv()保存数据时,您的class列中的数据被存储为字符串(string)而不是字典/JSON - Anurag Dabas
df_articles1.dtypes返回Class列的“object”类型。它应该返回字符串吗? - Theo75
我无法重现这个问题。您发布的代码可以正常运行,没有错误。 - RJ Adriaansen
2个回答

9

这是因为当你使用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'].map(eval)

最后:

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

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

注意:是的,根据this thread,使用eval是不好的,但在某些情况下,当您的数据混乱时,您只有一个选择:使用eval


8

虽然已被接受的答案是有效的,但使用eval是不好的做法

要解析类似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

如果字符串是单引号,请使用str.replace将其转换为双引号(从而成为有效的JSON),然后应用json.loads

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接