如何根据时间戳将多个 JSON 对象合并到一个 Python DataFrame 中?
How to merge multiple JSON objects into a Python DataFrame based on timestamp?
我有一个 graphql 查询,它 returns 一串 JSON 格式的数据,里面有 3 个单独的 JSON 对象。它看起来像这样:
{
"data": {
"readingsList": [
{
"value": 137,
"millis": 1651449224000
},
{
"value": 141,
"millis": 1651448924000
}
],
"messagesList": [
{
"value": 138,
"dateMillis": 1651445346000,
"text": "foo",
"type": "bar",
"field1": False
}
]
"userList": [
{
"userTimezone": "America/Los_Angeles"
}
]
}
}
我想做的是
- 根据时间(
millis
和dateMillis
)将前两个对象(readingsList
和messagesList
)合并到一个dataframe
- 将该时间转换为 UTC 日期时间值(例如 1651449224000 变为 2022-05-01 18:53:44)
- 根据来自
userList
的用户时区,将 UTC 日期时间值转换为用户的本地时间
期望的输出:
df.head(3)
datetime value text type field1 ...
2022-05-01 18:53:44 137 NA NA NA
2022-05-01 18:48:44 141 NA NA NA
2022-05-01 17:49:06 138 foo bar False
我可以执行第 2 步和第 3 步,但我不知道如何执行第 1 步。
如果我使用 json.loads()
和 pd.read_json()
转换字符串,我会得到以下输出:
import json
import pandas as pd
json_str = load_data_gql(...)
j = json.loads(json_str)
df = pd.read_json(j)
df.head()
data
groupsList [{'userTimezone': 'America/Los_Angeles'}]
messagesList [{'value': 138, 'dateMillis': 1651445346000, ...
readingsList [{'value': 137, 'millis': 1651449224000}, {'value'...
我现在怀疑答案与 json_normalize() 有某种关系,但我很难应用我在该文档中阅读的内容来正确导航我的 JSON 对象。
任何建议或帮助将不胜感激,在此先感谢您。
建议的解决方案:
在这种情况下合并数据帧可以通过 pandas.concat([df_1,df_2])
完成
这是我使用的代码:
import json
import pandas as pd
json_obj = json.load(open('json_str_file.json', 'r')) # if reading from file
# json_obj = json.loads(json_str) # if reading from a string
# create two separate frames from each nested dictionary object
df_1 = pd.DataFrame.from_dict(json_obj['data']['messagesList'])
df_2 = pd.DataFrame.from_dict(json_obj['data']['readingsList'])
# set the index to the column you want to merge them on
df_1.set_index('dateMillis', inplace=True)
df_2.set_index('millis', inplace=True)
# use pd.concat to stack the dataframes together
df_merged = pd.concat([df_1,df_2])
# fix field1 to be a boolean field
df_merged['field1'] = df_merged['field1'].astype(bool)
# confirm the result matches the target
print(df_merged)
输出
value text type field1
1651445346000 138 foo bar False
1651449224000 137 NaN NaN True
1651448924000 141 NaN NaN True
从这里您应该可以执行 post 中的第 2 步和第 3 步。
JSON
的问题
您提供的示例存在一些格式问题,可能会引起一些混淆。 messagesList
和 readingsList
需要用“,”分隔。另外 json.load()
不喜欢我示例中 False
的值。
这是重新格式化后的 JSON
{
"data": {
"readingsList": [
{
"value": 137,
"millis": 1651449224000
},
{
"value": 141,
"millis": 1651448924000
}
],
"messagesList": [
{
"value": 138,
"dateMillis": 1651445346000,
"text": "foo",
"type": "bar",
"field1": 0
}
],
"userList": [
{
"userTimezone": "America/Los_Angeles"
}
]
}
}
潜在的混淆:
- JSON 字符串格式可能不正确
json.loads()
returns 具有嵌套元素的 dict
类型的对象。
pd.read_json()
需要类型为 str
的对象
- 使用
pd.DataFrame.from_dict()
与 dict
对象一起使用,并允许您像这样处理嵌套组件:j['data']['messagesList']
我有一个 graphql 查询,它 returns 一串 JSON 格式的数据,里面有 3 个单独的 JSON 对象。它看起来像这样:
{
"data": {
"readingsList": [
{
"value": 137,
"millis": 1651449224000
},
{
"value": 141,
"millis": 1651448924000
}
],
"messagesList": [
{
"value": 138,
"dateMillis": 1651445346000,
"text": "foo",
"type": "bar",
"field1": False
}
]
"userList": [
{
"userTimezone": "America/Los_Angeles"
}
]
}
}
我想做的是
- 根据时间(
millis
和dateMillis
)将前两个对象(readingsList
和messagesList
)合并到一个dataframe - 将该时间转换为 UTC 日期时间值(例如 1651449224000 变为 2022-05-01 18:53:44)
- 根据来自
userList
的用户时区,将 UTC 日期时间值转换为用户的本地时间
期望的输出:
df.head(3)
datetime value text type field1 ...
2022-05-01 18:53:44 137 NA NA NA
2022-05-01 18:48:44 141 NA NA NA
2022-05-01 17:49:06 138 foo bar False
我可以执行第 2 步和第 3 步,但我不知道如何执行第 1 步。
如果我使用 json.loads()
和 pd.read_json()
转换字符串,我会得到以下输出:
import json
import pandas as pd
json_str = load_data_gql(...)
j = json.loads(json_str)
df = pd.read_json(j)
df.head()
data
groupsList [{'userTimezone': 'America/Los_Angeles'}]
messagesList [{'value': 138, 'dateMillis': 1651445346000, ...
readingsList [{'value': 137, 'millis': 1651449224000}, {'value'...
我现在怀疑答案与 json_normalize() 有某种关系,但我很难应用我在该文档中阅读的内容来正确导航我的 JSON 对象。
任何建议或帮助将不胜感激,在此先感谢您。
建议的解决方案:
在这种情况下合并数据帧可以通过 pandas.concat([df_1,df_2])
这是我使用的代码:
import json
import pandas as pd
json_obj = json.load(open('json_str_file.json', 'r')) # if reading from file
# json_obj = json.loads(json_str) # if reading from a string
# create two separate frames from each nested dictionary object
df_1 = pd.DataFrame.from_dict(json_obj['data']['messagesList'])
df_2 = pd.DataFrame.from_dict(json_obj['data']['readingsList'])
# set the index to the column you want to merge them on
df_1.set_index('dateMillis', inplace=True)
df_2.set_index('millis', inplace=True)
# use pd.concat to stack the dataframes together
df_merged = pd.concat([df_1,df_2])
# fix field1 to be a boolean field
df_merged['field1'] = df_merged['field1'].astype(bool)
# confirm the result matches the target
print(df_merged)
输出
value text type field1
1651445346000 138 foo bar False
1651449224000 137 NaN NaN True
1651448924000 141 NaN NaN True
从这里您应该可以执行 post 中的第 2 步和第 3 步。
JSON
的问题您提供的示例存在一些格式问题,可能会引起一些混淆。 messagesList
和 readingsList
需要用“,”分隔。另外 json.load()
不喜欢我示例中 False
的值。
这是重新格式化后的 JSON
{
"data": {
"readingsList": [
{
"value": 137,
"millis": 1651449224000
},
{
"value": 141,
"millis": 1651448924000
}
],
"messagesList": [
{
"value": 138,
"dateMillis": 1651445346000,
"text": "foo",
"type": "bar",
"field1": 0
}
],
"userList": [
{
"userTimezone": "America/Los_Angeles"
}
]
}
}
潜在的混淆:
- JSON 字符串格式可能不正确
json.loads()
returns 具有嵌套元素的dict
类型的对象。pd.read_json()
需要类型为str
的对象
- 使用
pd.DataFrame.from_dict()
与dict
对象一起使用,并允许您像这样处理嵌套组件:j['data']['messagesList']