算法知道事件在更大时间范围内的某个时间段内发生的频率 (Pandas)

Algorithm to know how often the event happened during some period of time within greater time range (Pandas)

例如,我有 Pandas 两列的数据集 df:['number'] 和 ['date']。在 ['number'] 列中放置各种数字,在 ['date'] 列中日期和时间,当数字出现时,以 Epoch Unix 时间戳格式放置。

如何统计某个数字,比如20,在100秒的时间内出现了15次以上? (整个时间范围(df['date'][n] - df['date'][0] 远大于 100 秒)

我编写了如下所示的 Python 代码。有用。但问题是,如果数据集非常大(数百万行)并且我正在寻找的事件发生在例如接近数据集末尾的地方,则需要花费很多时间才能获得结果。我怎样才能让它工作得更快?

count = 0
time = 0
length = len(df['number'])
for i in range(length):
    time = df['date'][i] + 100
    for j in range(1, length):
        if df['date'][j] > time:
            count = df['number'][(df['date'] >= df['date'][i]) & (df['date'] <= df['date'][j-1]) & (df['number'] == 20)].count()
            break
        if j == length - 1:
            count = df['number'][(df['date'] >= df['date'][i]) & (df['date'] <= df['date'][j]) & (df['number'] == 20)].count()
            break
            
    if count > 15:
        print('Number 20 appeared more than 15 times within the period of 100 seconds')
        break

我不遵循你代码的逻辑。对于给定的索引 i,您设置 date[i] + 100time 边界,然后在整个数据帧中查找时间大于该边界的行。

无论如何,我将从您的问题文本开始。下面统计给定区间内每个数字出现的最大次数。

# reproducible setup
np.random.seed(0)
n = 100
interval = pd.Timedelta(100, 's')
ratio = 10
df = pd.DataFrame({
    'date': pd.Series(
        np.random.uniform(0, n / ratio, n) * interval + pd.Timestamp('2000')
    ).dt.round('s'),
    'number': np.random.choice([0,10,20,30], n),
}).set_index('date').sort_index()

以上构建了一个 100 行的 DataFrame 随机日期和数字,例如:

>>> df.head()
                     number
date                       
2000-01-01 00:00:05      10
2000-01-01 00:00:19       0
2000-01-01 00:00:20      20
2000-01-01 00:00:20       0
2000-01-01 00:00:39       0

现在,这里有一个表达式,它使用 RollingGroupBy 来计算每个数字和日期在过去 100 秒内看到给定数字的次数:

z = df.assign(n=1).groupby('number')['n'].rolling(interval).sum().astype(int)

>>> z.head()
number  date               
0       2000-01-01 00:00:19    1
        2000-01-01 00:00:20    2
        2000-01-01 00:00:39    3
        2000-01-01 00:01:27    4
        2000-01-01 00:02:00    3
Name: n, dtype: int64

然后:

>>> z.groupby('number').max()
number
0     7
10    5
20    7
30    7
Name: n, dtype: int64

上面告诉使用,对于数字 20,在 100 秒间隔内出现的最大次数是 7,并且:

>>> z.groupby('number').idxmax().str[-1]
number
0     2000-01-01 00:03:03
10    2000-01-01 00:10:18
20    2000-01-01 00:01:59
30    2000-01-01 00:13:58

它发生在 2000-01-01 00:01:59

确实:

tmax = z.groupby('number').idxmax().str[-1][20]
zz = df[df['number'] == 20].truncate(before=tmax - interval, after=tmax)

>>> zz
                     number
date                       
2000-01-01 00:00:20      20
2000-01-01 00:01:04      20
2000-01-01 00:01:11      20
2000-01-01 00:01:34      20
2000-01-01 00:01:37      20
2000-01-01 00:01:42      20
2000-01-01 00:01:59      20

>>> len(zz)
7

速度

要测量速度,例如尝试在设置中替换:

n = 1_000_000

以后:

%timeit df.assign(n=1).groupby('number')['n'].rolling(interval).sum().astype(int)
# 350 ms ± 3.12 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

因此,100 万行不到 1/2 秒。