如何使用Python Pandas正确地对JSON进行规范化

17

我想要做的是通过Pandas加载外汇历史价格数据的json文件,并对该数据进行统计分析。我已经阅读了许多关于Pandas和解析json文件的主题。我希望将具有额外值和嵌套列表的json文件传递给pandas dataframe。

我获得了一个json文件'EUR_JPY_H8.json'

首先我导入所需的库,

import pandas as pd
import json
from pandas.io.json import json_normalize

然后加载json文件,

with open('EUR_JPY_H8.json') as data_file:    
data = json.load(data_file)

我有以下列表:

[{u'complete': True,
u'mid': {u'c': u'119.743',
  u'h': u'119.891',
  u'l': u'119.249',
  u'o': u'119.341'},
u'time': u'1488319200.000000000',
u'volume': 14651},
{u'complete': True,
u'mid': {u'c': u'119.893',
  u'h': u'119.954',
  u'l': u'119.552',
  u'o': u'119.738'},
u'time': u'1488348000.000000000',
u'volume': 10738},
{u'complete': True,
u'mid': {u'c': u'119.946',
  u'h': u'120.221',
  u'l': u'119.840',
  u'o': u'119.888'},
u'time': u'1488376800.000000000',
u'volume': 10041}]

然后我将列表传递给json_normalize。尝试获取在'mid'下的嵌套列表中的价格。

result = json_normalize(data,'time',['time','volume','complete',['mid','h'],['mid','l'],['mid','c'],['mid','o']])

但我的结果是这样的:

output

时间数据被拆分成了每一行的整数。

我查看了相关文档。我必须将字符串或列表对象传递给json_normalize的第二个参数。如何在不拆分时间戳的情况下传递它?

我期望输出的列为:

  index  |  time  | volumn  |  completed  |  mid.h  |  mid.l  |  mid.c  |  mid.o 
2个回答

27

您可以只传递data而不需要任何额外的参数。

df = pd.io.json.json_normalize(data)
df

   complete    mid.c    mid.h    mid.l    mid.o                  time  volume
0      True  119.743  119.891  119.249  119.341  1488319200.000000000   14651
1      True  119.893  119.954  119.552  119.738  1488348000.000000000   10738
2      True  119.946  120.221  119.840  119.888  1488376800.000000000   10041
如果您想更改列的顺序,请使用 df.reindex
df = df.reindex(columns=['time', 'volume', 'complete', 'mid.h', 'mid.l', 'mid.c', 'mid.o'])
df

                   time  volume  complete    mid.h    mid.l    mid.c    mid.o
0  1488319200.000000000   14651      True  119.891  119.249  119.743  119.341
1  1488348000.000000000   10738      True  119.954  119.552  119.893  119.738
2  1488376800.000000000   10041      True  120.221  119.840  119.946  119.888

5

在使用json.load()将其反序列化后,OP中的数据是一个嵌套字典的列表。对于pd.json_normalize()来说,这是一种理想的数据结构,因为它将字典列表转换并将每个字典展开成单独的行。因此,列表的长度决定了行数,而字典中键值对的总数则决定了列数。

但是,如果某个键下的值是一个列表,则不再适用上述规则,因为假定这些列表中的项需要分别放在各自的行中。例如,如果my_data.json文件如下:

# my_data.json
[
    {'price': {'mid': ['119.743', '119.891', '119.341'], 'time': '123'}},
    {'price': {'mid': ['119.893', '119.954', '119.552'], 'time': '456'}},
    {'price': {'mid': ['119.946', '120.221', '119.840'], 'time': '789'}}
]

然后,您需要将列表中的每个值放在其自己的行中。在这种情况下,您可以将这些列表的路径作为record_path=参数传递。此外,您可以使每个记录都具有其相应的元数据,其路径也可以作为meta=参数传递。

# deserialize json into a python data structure
import json
with open('my_data.json', 'r') as f:
    data = json.load(f)

# normalize the python data structure
df = pd.json_normalize(data, record_path=['price', 'mid'], meta=[['price', 'time']], record_prefix='mid.')

res

最终,pd.json_normalize() 无法处理比这种结构更复杂的内容。例如,如果它嵌套在另一个字典中,它就无法为上面的示例添加其他元数据。根据数据的不同,您很可能需要一个递归函数来解析它(FYI,pd.json_normalize() 也是一个递归函数,但它是针对一般情况的,并且对于许多特定对象无法工作)。

通常情况下,您需要结合使用 explode()pd.DataFrame(col.tolist()) 等方法来完全解析数据。

Pandas 还有一个方便的函数 pd.read_json(),但它甚至比 pd.json_normalize() 更受限制,因为它只能正确解析一个嵌套级别的 json 数组。与 pd.json_normalize() 不同,它在底层反序列化 json 字符串,因此您可以直接将路径传递给 json 文件(无需使用 json.load())。换句话说,以下两个语句产生相同的输出:

df1 = pd.read_json("my_data.json") 
df2 = pd.json_normalize(data, max_level=0)  # here, `data` is deserialized `my_data.json`
df1.equals(df2)  # True

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