如何根据时间戳将多个 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"
      }
    ]
  }
}

我想做的是

  1. 根据时间(millisdateMillis)将前两个对象(readingsListmessagesList)合并到一个dataframe
  2. 将该时间转换为 UTC 日期时间值(例如 1651449224000 变为 2022-05-01 18:53:44)
  3. 根据来自 userList
  4. 的用户时区,将 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

的问题

您提供的示例存在一些格式问题,可能会引起一些混淆。 messagesListreadingsList 需要用“,”分隔。另外 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']