使用 Pandas 数据框规范化包含 JSON 数据的列

7

我有一个Pandas数据框,其中一列包含JSON数据(JSON结构很简单:只有一级,没有嵌套数据):

ID,Date,attributes
9001,2020-07-01T00:00:06Z,"{"State":"FL","Source":"Android","Request":"0.001"}"
9002,2020-07-01T00:00:33Z,"{"State":"NY","Source":"Android","Request":"0.001"}"
9003,2020-07-01T00:07:19Z,"{"State":"FL","Source":"ios","Request":"0.001"}"
9004,2020-07-01T00:11:30Z,"{"State":"NY","Source":"windows","Request":"0.001"}"
9005,2020-07-01T00:15:23Z,"{"State":"FL","Source":"ios","Request":"0.001"}"

我的Pandas数据框

我希望将attributes列中的JSON内容标准化,使JSON属性成为数据框中的每一列。

ID,Date,attributes.State, attributes.Source, attributes.Request
9001,2020-07-01T00:00:06Z,FL,Android,0.001
9002,2020-07-01T00:00:33Z,NY,Android,0.001
9003,2020-07-01T00:07:19Z,FL,ios,0.001
9004,2020-07-01T00:11:30Z,NY,windows,0.001
9005,2020-07-01T00:15:23Z,FL,ios,0.001 

我一直在尝试使用Pandas json_normalize,它需要一个字典。所以,我想把attributes列转换成字典,但是并没有像预期的那样工作,因为字典的形式如下:

df.attributes.to_dict()

{0: '{"State":"FL","Source":"Android","Request":"0.001"}',
 1: '{"State":"NY","Source":"Android","Request":"0.001"}',
 2: '{"State":"FL","Source":"ios","Request":"0.001"}',
 3: '{"State":"NY","Source":"windows","Request":"0.001"}',
 4: '{"State":"FL","Source":"ios","Request":"0.001"}'}

归一化使用键(0、1、2等)作为列名,而不是JSON键。

我感觉我接近了答案,但还不能完全确定如何准确地执行。欢迎任何想法。

谢谢!

4个回答

4

Normalize 函数期望处理对象而不是字符串。

import json
import pandas as pd
df_final = pd.json_normalize(df.attributes.apply(json.loads))

这对我很有帮助。我有一个 .tsv 文件,使用 read_csv 方法读取。然后当我将 df 传递给 json_normalize 时,它只输出索引。我的列只是一个字符串。我将其转换为对象,然后就完成了!谢谢。 - yaach

1

您不需要先转换为字典。

尝试:

import pandas as pd

pd.json_normalize(df[‘attributes’])

1
嗨@Owen。我已经尝试过了,但是我遇到了一个错误: AttributeError: 'str' object has no attribute 'values 如果我尝试 pd.json_normalize(df[‘attributes’].values),它也会出现相同的问题。 - Wilmar
数据是如何导入的? - cutting_shapes
嗨@Owen,这只是一个简单的 import pandas as pd df = pd.read_csv('datafile.csv') - Wilmar
不确定这是否有帮助,似乎是类似的情况。如果没有,敬请谅解:https://dev59.com/MVUL5IYBdhLWcg3w3LUH - cutting_shapes
谢谢@Owen。那是一个有趣的帖子。但它并不符合我的需求。我拥有的数据不是一组字典,让它成为这样会让我处于与原始问题非常相似的位置。但我很感激你的努力。谢谢! - Wilmar

1
你可以用一行代码实现所需的输出:
df = pd.concat([df[['ID', 'Date']], pd.json_normalize(df['attributes'])], axis=1)

这是我问题的完美解决方案。非常感谢你的回答! - undefined

0

我找到了一个解决方案,但我对它并不是非常满意。我认为它非常低效。

import pandas as pd
import json

# Import full dataframe
df = pd.read_csv(r'D:/tmp/sample_simple.csv', parse_dates=['Date'])

# Create empty dataframe to hold the results of data conversion
df_attributes = pd.DataFrame()

# Loop through the data to fill the dataframe
for index in df.index:
    row_json = json.loads(df.attributes[index])
    normalized_row = pd.json_normalize(row_json)
    # df_attributes = df_attributes.append(normalized_row) (deprecated method) use concat instead
      df_attributes = pd.concat([df_attributes, normalized_row], ignore_index=True) 

# Reset the index of the attributes dataframe
df_attributes = df_attributes.reset_index(drop=True)

# Drop the original attributes column
df = df.drop(columns=['attributes'])

# Join the results
df_final = df.join(df_attributes)

# Show results
print(df_final)
print(df_final.info())

这给了我期望中的结果。但是,正如我所说,它有几个低效之处。首先,在for循环中的数据框追加操作。根据文档,最佳实践是先创建一个列表,然后再进行追加,但我无法想出如何在保持所需形状的同时完成此操作。欢迎所有批评和想法。


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