0

我的程序使用 array.fromfile() 将 420 万个无符号整数从二进制文件中读取到一个数组(脉冲)中。然后它遍历这些整数并基于模运算将它们附加到适当的列表位置(区域)中。目前,下面的循环大约需要 2 秒,但我希望它可以做得更快。我花了几个小时尝试不同的 numpy 方法,其中一些最终变慢了。我已经为各种功能计时,这绝对是瓶颈。有任何想法吗?

        for idx,val in enumerate(pulses):
            if (idx + 1)%nZones == 0 and idx != 0:
                zones[zone].append(val)            
                zone = 0
            else:
                zones[zone].append(val)
                zone += 1

例如:有 200 个区域,脉冲 1 进入区域 1,脉冲 2 进入区域 2,以此类推,直到我们到达第 200 个脉冲,脉冲 201 进入区域 1。

4

4 回答 4

2

看来您正在有效地将较长的信号分成等长的块。一种不同的思考方式是将向量重塑为数组。

在我的机器上,这种方法要快三个数量级(使用 iPython 的单元魔法):

设置:

pulses = random_integers(0, 1000, 4.2e6)
nZones = 200
zones = [[] for i in range(nZones)]

您的参考方法

%%timeit
zone = 0
for idx,val in enumerate(pulses):
    if (idx + 1)%nZones == 0 and idx != 0:
        zones[zone].append(val)            
        zone = 0
    else:
        zones[zone].append(val)
        zone += 1

1 个循环,最好的 3 个循环:每个循环 1.63 秒

%%timeit
zones = reshape(pulses, (len(pulses)/nZones, nZones)).T

100000 次循环,3 次中的最佳:每个循环 2.04 µs

如果您真的想要一个列表列表,那么您需要为转换支付相当多的费用。如果您担心速度,您可能真的不需要列表列表。

%%timeit
zones = reshape(pulses, (len(pulses)/nZones, nZones)).T.tolist()

1 个循环,最好的 3 个:每个循环 102 毫秒

于 2013-10-19T16:57:03.193 回答
1

np.reshape速度很快,但不会产生列表。

一些设置:

N_ZONES = 200
MAX_VALUE = 100
N_VALUES = 4.2e6 + np.random.randint(N_ZONES) # Ensure a random number

# Random set of ~4.2 million values
pulses = np.random.randint(0, MAX_VALUE, (N_VALUES))

由于我们不知道 pules 的总数可以被 200 整除,因此我们可能需要填充数组

# Pad pulses with negatives to have a size divisible by 200
PADDING = N_ZONES - pulses.shape[0] % N_ZONES
pulses_padded = np.hstack((pulses, np.zeros(PADDING)-1))

# Reshape
zones = pulses_padded.reshape((-1, N_ZONES)).T

最后一行PADDING的末尾将有负值


然后您可以转换回列表列表,尽管这很慢

# Convert back to lists (though this is slow)
zone_lists = [ [value for value in row if value >= 0] for row in zones]
于 2013-10-19T16:53:18.820 回答
0

FWIW,这是一个纯 Python 版本(以较小的值显示以进行测试)。出于识别目的,使用的脉冲值是从 1 开始的级数。

from itertools import cycle, izip
from math import ceil

nPulses = 100
pulses = range(1, nPulses+1)
nZones = 20
nZoneSize = int( ceil(len(pulses) / float(nZones)) )
zones = [[None for _ in xrange(nZoneSize)] for z in xrange(1, nZones+1)]

for i, (p, z) in enumerate(izip(pulses, cycle(zones))):
    z[i / nZones] = p

for zone in zones:
    print zone

输出:

[1, 21, 41, 61, 81]  
[2, 22, 42, 62, 82]  
[3, 23, 43, 63, 83]  
[4, 24, 44, 64, 84]  
[5, 25, 45, 65, 85]  
[6, 26, 46, 66, 86]  
[7, 27, 47, 67, 87]  
[8, 28, 48, 68, 88]  
[9, 29, 49, 69, 89]  
[10, 30, 50, 70, 90] 
[11, 31, 51, 71, 91] 
[12, 32, 52, 72, 92] 
[13, 33, 53, 73, 93] 
[14, 34, 54, 74, 94] 
[15, 35, 55, 75, 95] 
[16, 36, 56, 76, 96] 
[17, 37, 57, 77, 97] 
[18, 38, 58, 78, 98] 
[19, 39, 59, 79, 99] 
[20, 40, 60, 80, 100]
于 2013-10-19T17:38:40.483 回答
0

尝试:

for idx,val in enumerate(pulses):
    zones[zone%nZones].append(val)
    zone+=1
于 2013-10-19T18:08:13.737 回答