我想计算数组中某个范围的和(简单)——但我不想这样做,而是n次,应该求和的范围来自第二个数组。你知道吗
我有一个带有0和1的2D数组:
count = np.array(\
[[0,1,0,0,1,0,1],
[0,0,1,1,1,0,0]])
我构造了一个2D数组,该数组有一个字段,其中包含要在count数组上求和的范围。你知道吗
dtype=[..., ('ranges', 'u1', (2, 2)) , ...]
table['ranges']
看起来像这样:
[
[[1, 3], [0, 4]],
[[0, 0], [3, 4]],
[[0, 0], [2 4]],
[[0, 0], [3 4]],
[[3, 7], [1 5]]]
(通常在20到几百行之间)。你知道吗
这个例子的结果应该是
[2, # = (1 +0) + (0 + 0 +1)
1, # = ( ) + (1)
2, # = ( ) + (1 + 1)
1, # = ( ) + (1)
5] # = (0 + 1 +0 +1 ) + (0 + 1 + 1 + 1)
首先我从:
result = np.zeros(table.size, dtype=np.int)
for index, r in enumerate(table):
for index, range in enumerate(r['ranges']):
result[index] += np.sum(counts[index][range[0]:range[1]])
给出了正确的结果,但不是效率的例子。你知道吗
我还试图消除第二个循环,并将其放大一点:
result = np.zeros(table.size, dtype=np.int)
for index, (from1, to1, from2, to2) in \
enumerate(np.nditer(table['ranges'], flags=['external_loop'])):
counts[index] += np.sum(counts[0][from1:to1]) +\
np.sum(counts[1][from2:to2])
但是这些代码行仍然是应用程序花费大部分时间的地方。这个应用程序比这个要大一点,但是根据profiler的说法,大约有一半的时间花在这些行上。你知道吗
所以基本上我正在寻找一种方法来摆脱循环,并在numpy中实现这一切。 我在找一些类似
counts=np.sum(counts[1][table['ranges'][0][0]:table['ranges'][0][1])+np.sum(counts[2][table['ranges'][1][0]:table['ranges'][1][1])
但到目前为止还没有找到一个好的方法。你知道吗
更新进行了一些时间比较:
import numpy as np
import timeit as ti
table = np.empty(5,
dtype=[('s1', np.int8),
('ranges', 'u1', (2, 2)),
('s2', np.int16)])
table["ranges"] = [((1, 3), (0, 4)),
((0, 0), (3, 4)),
((0, 0), (2, 4)),
((0, 0), (3, 4)),
((3, 7), (1, 5))]
results = np.zeros(table.size)
counts = np.array([[0, 1, 0, 0, 1, 0, 1],
[0, 0, 1, 1, 1, 0, 0]])
# version one
def rv1(table, counts, results):
for row_index, r in enumerate(table):
for index, crange in enumerate(r['ranges']):
results[row_index] += np.sum(counts[index][crange[0]:crange[1]])
# version two
def rv2(table, counts, results):
for rowindex, (f1, t1, f2, t2) in \
enumerate(np.nditer(table['ranges'], flags=['external_loop'])):
results[rowindex] += np.sum(counts[0][f1:t1]) +\
np.sum(counts[1][f2:t2])
# version 3 (TomNash)
def rvTN(table, counts, results):
ranges=table["ranges"]
result=[
sum(counts[0][slice(*ranges[i][0])]) + sum(counts[1][slice(*ranges[i][1])])
for i in range(len(ranges))]
results+=result
results = np.zeros(table.size)
rv1(table, counts, results)
print ("rv1 result" , results)
results = np.zeros(table.size)
rv2(table, counts, results)
print ("rv2 result", results)
results = np.zeros(table.size)
rvTN(table, counts, results)
print ("slice*(TN) result", results)
print ("double loop time " , ti.timeit(lambda : rv1(table, counts, results)))
print ("nditer time " , ti.timeit(lambda : rv2(table, counts, results)))
print ("slice* time " , ti.timeit(lambda : rv3(table, counts, results)))
我明白了
double loop result [3. 1. 2. 1. 5.]
nditer result [3. 1. 2. 1. 5.]
slice* result [3. 1. 2. 1. 5.]
double loop time 42.41987561201677
nditer time 36.45269059110433
slice* time 24.102186055853963
所以Tomnash版本的速度快了30%。不幸的是,这还是有点慢。你知道吗
您可以使用
slice
和*args
来分解开始索引、停止索引和切片的列表。你知道吗我认为你的预期结果和你的指数有点出入,这就是我得到的。你知道吗
结果
相关问题 更多 >
编程相关推荐