循环转换/提取pandas DataFrame中的json数据不起作用
Posted
技术标签:
【中文标题】循环转换/提取pandas DataFrame中的json数据不起作用【英文标题】:Loop to convert/extract json data in pandas DataFrame not working 【发布时间】:2019-11-14 12:28:57 【问题描述】:我正在尝试执行 EDA 演练,并通过使用循环处理包含 json 数据的列来转换/提取数据框中的 json 数据。我这样做是通过为循环设置一个列表进行迭代,然后设置 for 循环以加载 json 数据并为每列的每一行提取名称字段。
在处理列表中的第一列后,它会抛出一个“JSON 对象必须是 str、bytes 或 bytearray,而不是 'list'”错误。
我尝试通过添加和删除列来修改列表以查看失败的位置,它始终适用于第一列,但之后放弃。对于一列的列表,这仍然适用。
我认为问题在于正在传递的“json.loads(data)”以某种方式仍然指向最后一个循环的结果(因为最后一个循环中的 json 被转换/提取到一个列表中)。但我不确定是否是这种情况,如果是,如何解决。
代码如下:
json_fields = ['genres', 'production_countries', 'spoken_languages']
for field in json_fields:
print(field)
movies_df[field] = movies_df[field].apply(lambda data:[row['name'] for row in json.loads(data)])
这是回溯:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-cc13bd0423f3> in <module>()
3 for field in json_fields:
4 print(field)
----> 5 movies_df[field] = movies_df[field].apply(lambda data:[row['name'] for row in json.loads(data)])
~/anaconda3/lib/python3.6/site-packages/pandas/core/series.py in apply(self, func, convert_dtype, args, **kwds)
2549 else:
2550 values = self.asobject
-> 2551 mapped = lib.map_infer(values, f, convert=convert_dtype)
2552
2553 if len(mapped) and isinstance(mapped[0], Series):
pandas/_libs/src/inference.pyx in pandas._libs.lib.map_infer()
<ipython-input-15-cc13bd0423f3> in <lambda>(data)
3 for field in json_fields:
4 print(field)
----> 5 movies_df[field] = movies_df[field].apply(lambda data:[row['name'] for row in json.loads(data)])
~/anaconda3/lib/python3.6/json/__init__.py in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
346 if not isinstance(s, (bytes, bytearray)):
347 raise TypeError('the JSON object must be str, bytes or bytearray, '
--> 348 'not !r'.format(s.__class__.__name__))
349 s = s.decode(detect_encoding(s), 'surrogatepass')
350
TypeError: the JSON object must be str, bytes or bytearray, not 'list'
这里是结果表的链接: https://imgur.com/a/yHDdFM8
Genres 是有效的列,另外两个是无效的列示例
编辑:这是我正在使用的表格的来源:https://www.kaggle.com/tmdb/tmdb-movie-metadata/
【问题讨论】:
您的 lambda 表达式为每一行返回 [row['name'] for row in json.loads(data)]。我猜您更希望将每个文档的名称分配给另一行,对吧? @jottbe,我很难理解您所说的文档是什么意思。您的意思是“数据”是指每行中包含的数据,因为它通过 for 循环? 那么目标是将图像中每个突出显示的列转换为名称列表而不是字典吗? @exlo,文档是指 json 文档(与行相同)。很抱歉混淆了这些条款。 @exlo 你能补充一下你在数据框中的阅读方式吗,当我使用movies_df = pandas.Dataframe.from_csv(filename)
然后运行相同的代码时,我没有遇到同样的问题。
【参考方案1】:
所以我认为“genre”列是表示 JSON 的字符串,而“production_countries”和“spoken_languages”列是包含 JSON 的字符串表示或已被解析为 python 字典的列表。
尝试将循环更改为
for field in json_fields:
print(field)
print(type(movies_df[field][0]))
print(type(movies_df[field][0][0]))
根据输出有几个解决方案
1。 “production_countries”和“spoken_languages”是字符串列表
如果上面的循环给你类似的东西
production_countries
<class 'list'>
<class 'str'>
那么“production_countries”中的每一行都是一个列表,列表中的每个元素都是一个字符串,应该可以使用以下代码将其解析为JSON。
for field in json_fields:
if field == 'genres':
movies_df[field] = movies_df[field].apply(lambda data: [row['name'] for row in json.loads(data)])
elif field == 'production_countries':
movies_df[field] = movies_df[field].apply(lambda data: [json.loads(row)['name'] for row in data])
2。 "production_countries" 和 "spoken_languages" 是 python 字典列表
如果第一个循环给你类似的东西
production_countries
<class 'list'>
<class 'dict'>
那么“production_countries”上的每一行都是一个列表,列表中的每个元素都是一个字典。那么以下应该可以工作
for field in json_fields:
if field == 'genres':
movies_df[field] = movies_df[field].apply(lambda data: [row['name'] for row in json.loads(data)])
elif field == 'production_countries':
movies_df[field] = movies_df[field].apply(lambda data: [row['name'] for row in data])
总结
如果上述方法不起作用,则列可能由其他数据结构组成。如果上述方法确实有效,最好更改数据加载到 panda 数据帧的方式,而不是使用上述解决方案。
【讨论】:
感谢调试提示!看起来 type 的输出实际上是 'production_countries以上是关于循环转换/提取pandas DataFrame中的json数据不起作用的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Pandas Dataframe 中的字符串转换为列表或字符数组?
在 for 循环中将 Python Dask 系列转换为列表或 Dask DataFrame