算法知道事件在更大时间范围内的某个时间段内发生的频率 (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] + 100
的 time
边界,然后在整个数据帧中查找时间大于该边界的行。
无论如何,我将从您的问题文本开始。下面统计给定区间内每个数字出现的最大次数。
# 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 秒。
例如,我有 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] + 100
的 time
边界,然后在整个数据帧中查找时间大于该边界的行。
无论如何,我将从您的问题文本开始。下面统计给定区间内每个数字出现的最大次数。
# 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 秒。