【问题标题】:python: group data within time seriespython:在时间序列内分组数据
【发布时间】:2019-02-25 14:31:12
【问题描述】:

给定以下数据库:

import pandas as pd
from time import strptime

data = {'num': ['B', 'A', 'B', 'A', 'B', 'A', 'B', 'C', 'B', 'A', 'C', 'B'],
        'dir': ['IN', 'IN', 'PASS', 'PASS', 'PASS', 'PASS', 'OUT', 'IN', 'IN', 'OUT', 'OUT', 'OUT'],
        'empty': [True, False, True, False, True, False, True, False, False, False, False, False],
        'station': [100, 1, 20, 20, 14, 14, 5, 65, 89, 8, 66, 11],
        'time': [strptime('20180115 00:25', '%Y%m%d %H:%M'),
                 strptime('20180115 00:30', '%Y%m%d %H:%M'),
                 strptime('20180115 01:10', '%Y%m%d %H:%M'),
                 strptime('20180115 01:10', '%Y%m%d %H:%M'),
                 strptime('20180115 02:10', '%Y%m%d %H:%M'),
                 strptime('20180115 02:10', '%Y%m%d %H:%M'),
                 strptime('20180115 03:33', '%Y%m%d %H:%M'),
                 strptime('20180115 03:33', '%Y%m%d %H:%M'),
                 strptime('20180115 03:34', '%Y%m%d %H:%M'),
                 strptime('20180115 04:10', '%Y%m%d %H:%M'),
                 strptime('20180115 04:11', '%Y%m%d %H:%M'),
                 strptime('20180115 10:10', '%Y%m%d %H:%M')]}

df = pd.DataFrame.from_dict(data)

我必须生成以下预期结果的列表:

   num  empty  station_from  station_to       time_from         time_to
0    B   True           100           5  20180115 00:25  20180115 03:33
1    A  False             1           8  20180115 00:30  20180115 04:10
2    C  False            65          66  20180115 03:33  20180115 04:11
3    B  False            89          11  20180115 03:34  20180115 10:10

说明: 这些是铁路车厢,每节车厢由 num 标识(即 A、B、C) 这些可以是收费的,也可以是空的(空栏) 列 dir 指示我们是否已选择或退出该特定汽车。可能有很多其他状态(如本例中的 PASS),但我们只对 IN 和 OUT 状态感兴趣 车站栏是事件发生的地方 时间列是事件发生的时间。

我必须对每个 IN 和 OUT 对之间的数据进行分组(或显示它们中的每一个的轨迹)并显示活动发生的地点和时间困难在于这不是“正常”分组,而是一种基于时间序列的分层结构(在同一天,可以多次装载和清空汽车)。

我不知道 pandas 是否是该练习的最佳结构,但数据库中有数亿条记录,性能至关重要。 (我们正在根据特定时间范围预先选择数据)

如何达到预期效果?

【问题讨论】:

  • 根据数据的大小和可用的计算资源,您可能需要研究并行线扫描算法。
  • 另外,这是批处理环境还是流环境?因为将其作为流式处理问题可能会在概念上更容易。
  • 好吧,我们可能会认为这是一个批处理过程,但如果响应时间是可以接受的(对于这个和十几个其他处理来说不到一分钟,但是那个处理的数据最多)那么整个过程将在线(这是最好的),用户点击“生成”,然后他将获得所需的列表
  • 关于规模,我每天可能有大约 100 000 个事件(IN、OUT、PASS 等)。该报告总是生成每月数据(因此每月大约有 300 万条记录),并且我们必须在数据库中将数据保存数年。
  • 如果您每月仅“按需”生成一次报告,那么对于 pandas 而言,这可能是一个太大的数据集。 (请记住,pandas 的计算模型完全在内存中)但是除非您的数据比您在此处说明的要多得多,否则像 dask dask.pydata.org/en/latest/ 这样的东西肯定能够处理它。 (dask 强烈模拟 pandas 界面,因此学习曲线应该非常小)

标签: python pandas pandas-groupby


【解决方案1】:

1) 过滤所有带有 'IN' 的行

2) 为每个匹配 numempty

的 'IN' 找到第一个下一个 'OUT'
result = df[df.dir=='IN'][['num','empty','station','time']].rename({'station':'station_from','time':'time_from'},axis='columns')
result[['station_to','time_to']] = result.apply(lambda r: df[(df.index>r.name) & (df.num==r.num) & (df.empty==r.empty) & (df.dir=='OUT')][['station','time']].iloc[0,:], axis=1)

print(result)

  num  empty  station_from                           time_from  station_to  \
0   B   True           100  (2018, 1, 15, 0, 25, 0, 0, 15, -1)           5   
1   A  False             1  (2018, 1, 15, 0, 30, 0, 0, 15, -1)           8   
7   C  False            65  (2018, 1, 15, 3, 33, 0, 0, 15, -1)          66   
8   B  False            89  (2018, 1, 15, 3, 34, 0, 0, 15, -1)          11   

                               time_to  
0   (2018, 1, 15, 3, 33, 0, 0, 15, -1)  
1   (2018, 1, 15, 4, 10, 0, 0, 15, -1)  
7   (2018, 1, 15, 4, 11, 0, 0, 15, -1)  
8  (2018, 1, 15, 10, 10, 0, 0, 15, -1)

【讨论】:

  • 哇!看起来不错!我有 2 个问题: 1:什么是 r.name?为什么要与指数相比? 2:这个选项(df.empty==r.empty)是不是如果几个IN/OUT轨道都是空的或充电的,会产生错误的结果?您的解决方案似乎将它们组合在一起。我是对的还是我错过了什么?实际上,无论空状态如何,我们都应该在 IN 之后立即执行第一个 OUT 事件
  • r.name 是在对行使用应用时访问行号。我不确定 empy 是否应该匹配,所以添加为条件。您可以删除 (df.emply==r.empty) 条件,但为了清楚起见,最好在结果表中将其重命名为 empty_from
猜你喜欢
  • 2021-02-11
  • 2020-06-18
  • 1970-01-01
  • 2021-01-21
  • 1970-01-01
  • 2019-02-24
  • 1970-01-01
  • 2015-03-07
  • 2019-07-15
相关资源
最近更新 更多