首页 > 解决方案 > 在 python 中处理时间序列数据:对一个时间段的序列求和和聚合

问题描述

我试图弄清楚如何可视化一些传感器数据。我每 5 分钟为多个设备收集一次数据,存储在一个看起来像这样的 JSON 结构中(请注意,我无法控制数据结构):

[
  {
    "group": { "id": "01234" },
    "measures": {
      "measures": {
        "...device 1 uuid...": {
          "metric.name.here": {
            "mean": [
              ["2019-04-17T14:30:00+00:00", 300, 1],
              ["2019-04-17T14:35:00+00:00", 300, 2],
              ...
            ]
          }
        },
        "...device 2 uuid...": {
          "metric.name.here": {
            "mean": [
              ["2019-04-17T14:30:00+00:00", 300, 0],
              ["2019-04-17T14:35:00+00:00", 300, 1],
              ...
            ]
          }
        }
      }
    }
  }
]

表单的每个元组["2019-04-17T14:30:00+00:00", 300, 0]都是[timestamp, granularity, value]. 设备按项目 ID 分组。在任何给定的组中,我想获取多个设备的数据并将它们汇总在一起。例如,对于上述示例数据,我希望最终系列看起来像:

["2019-04-17T14:30:00+00:00", 300, 1],
["2019-04-17T14:35:00+00:00", 300, 3],

该系列的长度不一定相同。

最后,我想将这些测量结果汇总为每小时样本。

我可以得到这样的个人系列:

with open('data.json') as fd:
  data = pd.read_json(fd)

for i, group in enumerate(data.group):
    project = group['project_id']
    instances = data.measures[i]['measures']
    series_for_group = []
    for instance in instances.keys():
        measures = instances[instance][metric][aggregate]

        # build an index from the timestamps
        index = pd.DatetimeIndex(measure[0] for measure in measures)

        # extract values from the data and link it to the index
        series = pd.Series((measure[2] for measure in measures),
                           index=index)

        series_for_group.append(series)

在外for循环的底部,我有一个pandas.core.series.Series对象数组,代表与当前组相关的不同测量集。我希望我可以像 in 一样简单地将它们添加在一起,total = sum(series_for_group)但这会产生无效数据。

  1. 我是否正确地阅读了这些数据?这是我第一次与 Pandas 合作;我不确定(a)创建一个索引,然后(b)填充数据是否是正确的过程。

  2. 我将如何成功地将这些系列总结在一起?

  3. 我如何将这些数据重新采样为 1 小时间隔?看看这个问题,看起来.groupby.agg方法似乎很有趣,但是从那个例子中并不清楚如何指定间隔大小。

更新 1

也许我可以使用concatand groupby?例如:

final = pd.concat(all_series).groupby(level=0).sum()

标签: pythonpandastime-series

解决方案


我在评论中建议做这样的事情:

result = pd.DataFrame({}, columns=['timestamp', 'granularity', 'value',
                               'project', 'uuid', 'metric', 'agg'])
for i, group in enumerate(data.group):
    project = group['id']
    instances = data.measures[i]['measures']

    series_for_group = []


    for device, measures in instances.items():
        for metric, aggs in measures.items():
            for agg, lst in aggs.items():
                sub_df = pd.DataFrame(lst, columns = ['timestamp', 'granularity', 'value'])
                sub_df['project'] = project
                sub_df['uuid'] = device
                sub_df['metric'] = metric
                sub_df['agg'] = agg

                result = pd.concat((result,sub_df), sort=True)

# parse date:
result['timestamp'] = pd.to_datetime(result['timestamp'])

这导致数据看起来像这样

    agg     granularity         metric  project     timestamp           uuid                value
0   mean    300     metric.name.here    01234   2019-04-17 14:30:00     ...device 1 uuid...     1
1   mean    300     metric.name.here    01234   2019-04-17 14:35:00     ...device 1 uuid...     2
0   mean    300     metric.name.here    01234   2019-04-17 14:30:00     ...device 2 uuid...     0
1   mean    300     metric.name.here    01234   2019-04-17 14:35:00     ...device 2 uuid...     1

然后你可以做整体聚合

result.resample('H', on='timestamp').sum()

这使:

timestamp
2019-04-17 14:00:00    4
Freq: H, Name: value, dtype: int64

或 groupby 聚合:

result.groupby('uuid').resample('H', on='timestamp').value.sum()

这使:

uuid                 timestamp          
...device 1 uuid...  2019-04-17 14:00:00    3
...device 2 uuid...  2019-04-17 14:00:00    1
Name: value, dtype: int64

推荐阅读