python - 在python中计算重叠滑动窗口中的值
问题描述
给定一个排序值数组 , 和一个范围数组 ,a
计算每个范围 ,中有多少个值的最有效方法是什么? bins
a
rng
bins
目前我正在做以下事情:
def sliding_count(a, end, window, start=0, step=1):
bins = [(x, x + window) for x in range(start, (end + 1) - window, step)]
counts = np.zeros(len(bins))
for i, rng in enumerate(bins):
count = len(a[np.where(np.logical_and(a>=rng[0], a<=rng[1]))])
counts[i] = count
return counts
a = np.array([1, 5, 8, 11, 14, 19])
end = 20
window = 10
sliding_count(a, end, window)
返回预期的数组
array([3., 4., 3., 3., 4., 4., 3., 3., 3., 3., 3.])
但我觉得必须有一种更有效的方法来做到这一点?
解决方案
import numpy as np
def alt(a, end, window, start=0, step=1):
bin_starts = np.arange(start, end+1-window, step)
bin_ends = bin_starts + window
last_index = np.searchsorted(a, bin_ends, side='right')
first_index = np.searchsorted(a, bin_starts, side='left')
return last_index - first_index
def sliding_count(a, end, window, start=0, step=1):
bins = [(x, x + window) for x in range(start, (end + 1) - window, step)]
counts = np.zeros(len(bins))
for i, rng in enumerate(bins):
count = len(a[np.where(np.logical_and(a>=rng[0], a<=rng[1]))])
counts[i] = count
return counts
a = np.array([1, 5, 8, 11, 14, 19])
end = 20
window = 10
print(sliding_count(a, end, window))
# [3. 4. 3. 3. 4. 4. 3. 3. 3. 3. 3.]
print(alt(a, end, window))
# [3 4 3 3 4 4 3 3 3 3 3]
alt 的工作原理:
生成 bin 的起始值和结束值:
In [73]: bin_starts = np.arange(start, end+1-window, step); bin_starts
Out[73]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
In [74]: bin_ends = bin_starts + window; bin_ends
Out[74]: array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
由于a
按排序顺序,您可以使用np.searchsorted
查找第一个和最后一个索引bin_starts
以及bin_ends
每个值a
适合的位置:
In [75]: last_index = np.searchsorted(a, bin_ends, side='right'); last_index
Out[75]: array([3, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6])
In [76]: first_index = np.searchsorted(a, bin_starts, side='left'); first_index
Out[76]: array([0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3])
这count
只是指数的差异:
In [77]: last_index - first_index
Out[77]: array([3, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3])
这是一个perfplot比较 与 的性能alt
作为sliding_count
长度的函数a
:
import perfplot
def make_array(N):
a = np.random.randint(10, size=N)
a = a.cumsum()
return a
def using_sliding(a):
return sliding_count(a, end, window)
def using_alt(a):
return alt(a, end, window)
perfplot.show(
setup=make_array,
kernels=[using_sliding, using_alt],
n_range=[2**k for k in range(22)],
logx=True,
logy=True,
xlabel='len(a)')
Perfplot 还检查返回的值是否using_sliding
等于返回的值using_alt
。
Matt Timmermans 的想法“从那个箱子的计数中减去position_in_a
”触发了这个解决方案。
推荐阅读
- python - 熊猫 - 提取方法不匹配任何东西
- django - 如何在 django 模型中进行 2 层深度反向关系?
- casting - 我可以在 C89 中将 void * 转换为 ptrdiff_t 吗?
- flutter - 防止 PageView 来自 ScrollNotification 监听器 Flutter
- c# - 如何全局使用 MongoDB 连接
- python - 另一个数据集的 Django 查询过滤器
- apache - 是否可以让地址栏中的域名包含大写字母?
- swift - 如何在 Swift 中对视图的层进行排序
- solidworks - 如何删除从CATIA导入的Solidworks装配模型的某些组件
- python - pyspark 的 Python Pulp 错误:类型之间不支持的操作