【问题标题】:filter numpy array of datetimes by frequency of occurance按出现频率过滤 numpy 日期时间数组
【发布时间】:2016-07-25 16:57:49
【问题描述】:

我有一个包含超过 200 万条记录的数组,每条记录都有一个 datetime.datetime 格式的 10 分钟解析时间戳,以及其他列中的几个其他值。

我只想保留时间戳在数组中出现 20 次或更多次的记录。最快的方法是什么?我有足够的 RAM,所以我正在寻找处理速度。

我在列表理解中尝试了 [].count() ,但开始失去等待它完成的生活意愿。我也试过 numpy.bincount() 但不幸的是它不喜欢 datetime.datetime

任何建议将不胜感激。 谢谢!

【问题讨论】:

  • pandas 可能会在 O(n) 时间内完成,所以我添加了标签。
  • 你能举一个非常小的例子来说明你的数组是什么样的吗? 3-4 个元素应该给我们一个足够好的想法。
  • 使用 pandas 并在时间戳上做一个 groupBy

标签: python datetime numpy pandas filtering


【解决方案1】:
  1. Sort你的数组
  2. 通过一次计算连续出现的次数,并过滤frequency >= 20

运行时间是 O(nlog(n)),而您的列表理解可能是 O(n**2)...这对 200 万个条目有很大影响。

根据数据的结构,您可能只能从保存它的 numpy 数组中对轴和所需数据进行排序。

【讨论】:

  • 有没有一种无需遍历数据就能快速计算出现次数的方法?
  • 没有。您必须通过每个条目来过滤它,但是,如果首先对数据进行排序,这非常快。
【解决方案2】:

根据以下建议,我正在编辑此内容以包含使用 np.unique 的时间安排。这是迄今为止最好的解决方案

In [10]: import pandas as pd
         import numpy as np
         from collections import Counter

         #create a fake data set 
         dates = pd.date_range("2012-01-01", "2015-01-01", freq="10min")
         dates = np.random.choice(dates, 2000000, replace=True)

根据下面的建议,以下是迄今为止最快的:

In [32]: %%timeit
         values, counts = np.unique(dates, return_counts=True)
         filtered_dates = values[counts>20]
         10 loops, best of 3: 150 ms per loop

使用计数器,您可以创建每个项目计数的字典,然后将其转换为 pd.Series 以进行过滤

In [11]: %%timeit
         foo = pd.Series(Counter(dates))
         filtered_dates = np.array(foo[foo > 20].index)
         1 loop, best of 3: 12.3 s per loop

这对于包含 200 万个项目的数组来说还算不错,与以下相比:

In [12]: dates = list(dates)
         filtered_dates = [e for e in set(dates) if dates.count(e) > 20]

我不会等待列表理解版本完成...

【讨论】:

    【解决方案3】:

    其实可以试试np.unique。在 numpy v1.9+ 中,unique 可以返回一些额外内容,例如 unique_indices、unique_inverse、unique_counts。

    如果你想使用 pandas,它会很简单而且可能很快。您可以使用groupby filter。比如:

    out = df.groupby('timestamp').filter(lambda x: len(x) > 20)
    

    【讨论】:

      【解决方案4】:

      Numpy 在这些类型的操作上比 pandas 慢,就像 np.unique 排序一样,而 pandas 中的机器不需要。此外,这更惯用。

      熊猫

      In [22]: %%timeit
         ....: i = Index(dates)
         ....: i[i.value_counts()>20]
         ....: 
      10 loops, best of 3: 78.2 ms per loop
      
      In [23]: i = Index(dates)
      
      In [24]: i[i.value_counts()>20]
      Out[24]: 
      DatetimeIndex(['2013-06-16 20:40:00', '2013-05-28 03:00:00', '2013-10-31 19:50:00', '2014-06-20 13:00:00', '2013-07-08 21:40:00', '2012-02-26 17:00:00', '2013-01-02 15:40:00', '2012-08-24 02:00:00',
                     '2014-10-17 08:20:00', '2012-07-27 20:10:00',
                     ...
                     '2014-08-07 05:10:00', '2014-05-21 08:10:00', '2014-03-09 12:50:00', '2013-05-10 02:30:00', '2013-04-15 20:20:00', '2012-06-23 05:20:00', '2012-07-06 16:10:00', '2013-02-14 12:20:00',
                     '2014-10-27 03:10:00', '2013-09-04 12:00:00'],
                    dtype='datetime64[ns]', length=2978, freq=None)
      
      In [25]: len(i[i.value_counts()>20])
      Out[25]: 2978
      

      Numpy(来自其他解决方案)

      In [26]: %%timeit
               values, counts = np.unique(dates, return_counts=True)
               filtered_dates = values[counts>20]
         ....: 
      10 loops, best of 3: 145 ms per loop
      
      In [27]: filtered_dates = values[counts>20]
      
      In [28]: len(filtered_dates)
      Out[28]: 2978
      

      【讨论】:

      • 同意,这是迄今为止最好的解决方案,只要 pandas 可用。
      【解决方案5】:

      感谢您的所有建议。

      我最终用字典做了一些完全不同的事情,发现它的处理速度要快得多。

      我创建了一个字典,其中一组唯一的时间戳作为键,空列表作为值,然后在无序列表(或数组)中循环一次,并用我想要计算的值填充值列表。

      再次感谢!

      【讨论】:

        猜你喜欢
        • 2013-01-08
        • 2013-10-20
        • 1970-01-01
        • 1970-01-01
        • 2021-09-01
        • 2021-12-27
        • 1970-01-01
        • 2018-01-25
        • 2017-05-28
        相关资源
        最近更新 更多