Python/Numpy查找长度变量跨度
考虑形状Python/Numpy查找长度变量跨度,python,algorithm,performance,numpy,scipy,Python,Algorithm,Performance,Numpy,Scipy,考虑形状(n,)单调递增的numpy数组 我的问题是有效地提取每个span(i,j),以便: X[i:j].sum() >= v and X[i:j-1].sum() < v 其中: list(variable_length_spans(X,10)) [(0, 3), (1, 3), (2, 4), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)] 这必须是一种更有效/更优雅的方式。然而,我可以找到方法。如有任何建议,我们将不胜感激
(n,)
单调递增的numpy数组
我的问题是有效地提取每个span(i,j)
,以便:
X[i:j].sum() >= v and X[i:j-1].sum() < v
其中:
list(variable_length_spans(X,10))
[(0, 3), (1, 3), (2, 4), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)]
这必须是一种更有效/更优雅的方式。然而,我可以找到方法。如有任何建议,我们将不胜感激
F
更新#1:时间安排
使用20K随机元素(10次运行的平均结果):
- 可变长度跨度:0.009332秒
- 戴维斯跨度:0.009259秒
- 广播时间:1.896222秒
- 可变长度跨度:0.528101秒
- 戴维斯大学广播:0.534576秒
def spans(X, v):
n, = X.shape
i = 0
total = 0
for j in xrange(0, n):
total += X[j]
while total >= v:
yield (i, j+1)
total -= X[i]
i += 1
基于小波变换的矢量化方法- 样本输入、输出-
In [212]: X
Out[212]: array([ 2, 3, 7, 19, 110, 112, 120, 140, 161])
In [213]: v
Out[213]: 10
In [214]: out
Out[214]:
array([[0, 3],
[1, 3],
[2, 4],
[3, 4],
[4, 5],
[5, 6],
[6, 7],
[7, 8],
[8, 9]])
错别字,对不起,我指的是X而不是dt。没有返回,因为变量_length_span是一个生成器(注意yield语句)。感谢您的编辑!那么,问题中列出的循环代码真的可以实现伪代码:
X[j]-X[i]>=v和X[j-1]-X[i]
?这个循环代码有很多求和,我在伪代码中没有看到。啊,对了,谢谢你的澄清。这个形状不是(n,1)
;这是一个一维数组。据我所知,你的版本和我的版本具有相同的复杂性(多亏了我在内部for循环中使用的break语句)。我说得对吗?最坏的情况下不是。例如,假设n=100,X=[1,1,1,…,100000000]。然后你的解决方案需要大约n(n-1)/2次循环迭代,而我的解决方案需要大约2n次循环迭代。好的,明白了,这比我的解决方案要好。然而,两者的运行时间都非常相同。是否存在更好的解决方案?它们的运行时间不同。与二次型相比,线性型是一个显著的改进。解决方案非常优雅,但是如果X增长,diff=cumsums[:,None]-cumsums可能会耗尽我的内存。@FrançoisKawala是的,它具有向量化的固有性质,需要足够的内存一次性完成任务。你的X有多大?我的X大约是1e5。我对我们的方法进行了计时(timeit),似乎嵌套循环更快。(10倍平均值,X.shape==(1e4,))可变长度跨度:0.004613/广播跨度:0.456812。这有意义吗?@FrançoisKawala是的,如果输入数据在求和的早期就被破坏了,那么向量化方法就不会有什么好处。有了这个矢量化的解决方案,我们创建了所有的求和和和跨度(微分),然后一次检查,但遗憾的是没有从您的案例中受益。好吧,很高兴知道!我天真地认为,我对for循环所做的一切都会比向量化方法慢。我已经根据我的数据绘制了随机值进行了测试,因此我想我会坚持使用迭代方法进行测试。
def spans(X, v):
n, = X.shape
i = 0
total = 0
for j in xrange(0, n):
total += X[j]
while total >= v:
yield (i, j+1)
total -= X[i]
i += 1
# Get cumulative summations
cumsums = X.cumsum()
# Elementwise subtractions between cumsums & its one place shifted version
diffs = cumsums[:,None] - np.append(0,cumsums[:-1])
# Detect cumulative summation span check
mask = diffs >= v
# Get valid mask for later selection purpose
valid = mask.any(0)
# Get first trigger indices
max_idx = np.argmax(mask,0)+1
# Concatenate row indices alongwith trigger ones for final output
out = np.column_stack((np.arange(max_idx.size),max_idx))[valid]
In [212]: X
Out[212]: array([ 2, 3, 7, 19, 110, 112, 120, 140, 161])
In [213]: v
Out[213]: 10
In [214]: out
Out[214]:
array([[0, 3],
[1, 3],
[2, 4],
[3, 4],
[4, 5],
[5, 6],
[6, 7],
[7, 8],
[8, 9]])