【问题标题】:Grouping data by frequency按频率分组数据
【发布时间】:2013-03-25 07:16:30
【问题描述】:

我做了一个代码,它在下面生成随机数,并将它们保存在一个 csv 中,如下所示,我正在尝试按函数学习分组。例如,我想按时间戳对这些组进行总和或平均值。我是 Python 新手,但我找不到任何开始的地方。 Ulitmately 我想做同样的事情,但 1 分钟或 5 分钟(从 00:00:00 开始每 5 分钟一次,在我下面的示例中没有足够的数据,但会做类似 13:35:00 到 13:40:00 的事情下一个 13:40:00 包括到 13:45:00 排除等),我想我可以计算出从时间戳中提取分钟部分的 1 分钟,但 5 分钟似乎很复杂。不要求复制粘贴代码,但我不知道从哪里开始说实话。

级别时间戳 99 2013 年 3 月 4 日 13:37:20 98 2013 年 3 月 4 日 13:37:20 98 2013 年 3 月 4 日 13:37:20 99 2013 年 3 月 4 日 13:37:20 105 2013 年 3 月 4 日 13:37:20 104 2013 年 3 月 4 日 13:37:20 102 2013 年 3 月 4 日 13:37:21 102 2013 年 3 月 4 日 13:37:21 103 2013 年 3 月 4 日 13:37:22 82 2013 年 3 月 4 日 13:37:23 83 2013 年 3 月 4 日 13:37:23 82 2013 年 3 月 4 日 13:37:23 83 2013 年 3 月 4 日 13:37:23 54 2013 年 3 月 4 日 13:37:24 55 2013 年 3 月 4 日 13:37:24 54 2013 年 3 月 4 日 13:37:24 55 2013 年 3 月 4 日 13:37:24 56 2013 年 3 月 4 日 13:37:25 57 2013 年 3 月 4 日 13:37:25

【问题讨论】:

  • 只是一个小问题 - 它看起来像是制表符分隔,而不是逗号分隔(csv 代表逗号分隔值)。
  • 否则,我对您要完成的工作感到有些困惑 - 您能否举例说明结果数据集的外观?
  • 我试图通过时间戳只获取一行,无论这是总和还是平均值

标签: python group-by timestamp time-series


【解决方案1】:

可以用 itertools 完成 http://docs.python.org/2/library/itertools.html#itertools.groupby

但要小心:

每次key的值产生一个break或者new group 功能变化(这就是为什么通常需要排序 数据使用相同的键功能)。

示例用法:

如果您的数据已作为 Level 、时间戳对的列表进行处理。

data = [(99, '03/04/2013 13:37:20'), (98,  '03/04/2013 13:37:20'), ...]

并且您想以 5 分钟的间隔按数据对组进行 AVG

data.sort(key=lambda i: i[1]) # sort with timestamp
results = []

def keyfunc(timestamp, interval = 5*60):
    # defined a key function.
    # 1. parse the datetime string to datetime object
    # 2. count the time delta (seconds)
    # 3. divided the time delta with interval, which is (6*60) here
    xt = datetime(2013, 4,3)
    dt = datetime.strptime(timestamp, '%d/%m/%Y %H:%M:%S')
    delta_second = int((dt - xt).total_seconds())
    normalize_second = (delta_second / interval) * interval
    return xt + timedelta(seconds=normalize_second)

for k, g in groupby(data, key=lambda i: keyfunc(i[1])):
    # k would be time interval "03/04/2013 13:30:00", "03/04/2013 13:35:00" .... 
    # g would be the level, timestamp pair belong to the interval
    avg_level = sum([x[0] for x in g]) / len(g)
    results.append((k, avg_level))

编辑1

groupby 函数中使用的keyfunc 告诉如何将项目分组。 如果两个 item 的 key function 的返回值相同,它们将被放在同一个 group 中。 (仅当这些项目已排序时)

>>> keyfunc('03/04/2013 13:37:20')
datetime.datetime(2013, 4, 3, 13, 35)

>>> keyfunc('03/04/2013 13:37:30')
datetime.datetime(2013, 4, 3, 13, 35)

# the return value are the same, so 03/04/2013 13:37:20 and 03/04/2013 13:37:30
# will be consider in the same group. 

【讨论】:

  • lucemia,对不起,但我很难理解 keyfunc 的目的是什么,我认为这是因为 groupby 需要一个函数作为键?但是,由于您将 xt 作为初始日期,然后您提供了系列的时间戳作为参数,它返回您的系列的时间戳?当然,我一定是遗漏了一些东西。我认为 dt= 和 normalize_second = 为什么要除然后乘以区间?
  • keyfunc 告诉python如何划分这些项目。它可以分为多种方式,因此我们需要指定正确的方式。查看我的编辑
  • 正确方式是什么意思?将时间戳除以间隔?
  • 对,你必须告诉 groupby 函数将时间戳除以 1 分钟、5 分钟、10 分钟、30 分钟或...等。
【解决方案2】:

有几种方法可以解决这个问题,但您实际上是在“分箱”。我会分几步来处理它:

你不想自己用字符串操作来解析时间,它会在你的脸上爆炸;相信我!将时间戳解析为日期时间对象(谷歌应该给你一个很好的答案)。一旦你有了它,你就可以做很多有趣的事情,比如比较两次。

现在您已经有了日期时间对象,您可以开始“装箱”它们了。我假设记录是有序的。从第一条记录的时间“03/04/2013 13:37:20”开始,并在“03/04/2013 13:37:00”处创建一个新的日期时间对象[提示:在你的日期时间对象上设置秒数=0读入]。这是您的第一个“bin”的开始。现在为您的开始日期时间添加一分钟 [提示:endDT = startDT + timedelta(seconds=60)],这就是您的第一个 bin 的结束。

现在开始检查您的记录,检查记录是否小于您的 endDT,如果是,请将其添加到该 bin 的列表中。如果记录大于您的 endDT,则您在下一个 bin 中。要启动新的 bin,请在 endDT 中增加一分钟并创建一个新列表来保存这些项目并在循环中继续前进。

完成循环后,您可以在列表上运行 max/min/avg。理想情况下,您会将列表存储在类似于 {datetimeObject : [34, 23, 45, 23]} 的字典中。这将使打印和分类变得容易。

这不是最有效/最灵活/最酷的方式,但我认为它可能是最有帮助的开始。

【讨论】:

    猜你喜欢
    • 2020-04-11
    • 2016-06-30
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多