Python:加快缓慢的 for 循环计算 (np.append)
Python: Speeding up a slow for-loop calculation (np.append)
我有一个名为 "cmp_twtt_amp_rho" 的输入文件,它有 7795074 行长。
我想计算每条线的声速 c,其中:
c(i) = rho(i-1) * c(i-1) * (-1-amp(i)) / rho(i) * (amp(i)-1)
使用初始猜测 c=1450。
我写了一个 for 循环,我相信它会起作用,但是它会随着时间的推移变得越来越慢,以至于 运行 在当前格式下是不可想象的。
有人可以帮我加快这段代码的速度吗?
data=np.genfromtxt('./cmp_twtt_amp_rho')
cmp_no=data[:,[0]]
twtt=data[:,[1]]
amp=data[:,[2]]
rho=data[:,[3]]
cs=[]
for i in range(1,len(amp-1)):
if i == 1:
print "Using an initial guess of 1450 m/s"
c = (rho[i-1]*1450*(-1-amp[i]))/(rho[i]*(1-amp[i]))
cs = np.append(c,cs)
elif twtt[i] == 0:
print "Reached new cmp #: ",cmp_no[i],"as twwt has re-started at ",twtt[i]
c = 1450
cs = np.append(c,cs)
else:
print i
c = (rho[i-1]*cs[i-1]*(-1-amp[i]))/(rho[i]*(1-amp[i]))
cs = np.append(c,cs)
print min(cs), max(cs)
print len(cs)
Numpy 数组并不是真的要追加(numpy 需要每次分配一个完整的新数组并将旧数据复制过来)。您可能不想循环执行此操作。
最好使用专为此类事情设计的数据结构——通常 python 的 list
可以很好地处理追加,因此我建议您将数据存储在一个列表并随时附加到它。然后在最后,如果你需要完整的数据集作为数组,你可以在那个时候转换回来。
我建议只更改为 cs.append(c)
而不是 cs = np.append(c, cs)
np.append
必须重新分配整个数组, 不好,但不是唯一的问题。您将 cs
附加到 c
而不是相反,这意味着 cs
将被反转并且 cs[i-1]
实际上是第一个 c
.
通常预分配数组更好:
cs = np.zeros(len(amp-1))
然后直接设置值:
cs[i] = c
像这样应该会快一点:
cs=np.zeros(len(amp-1))
print "Using an initial guess of 1450 m/s"
cs[1] = (rho[i-1]*1450*(-1-amp[i]))/(rho[i]*(1-amp[i]))
for i in range(2,len(amp-1)):
if twtt[i] == 0:
print "Reached new cmp #: ",cmp_no[i],"as twwt has re-started at ",twtt[i]
cs[i] = 1450
else:
print i
cs[i] = (rho[i-1]*cs[i-1]*(-1-amp[i]))/(rho[i]*(1-amp[i]))
追加到数组真的很慢,因为你每次都必须分配一个全新的数组。循环执行几乎总是会降低性能。
无需在循环中追加,甚至根本不使用 Python 级循环,您可以使用向量化运算和累积积更快地完成此操作:
multipliers = rho[:-1] * (-1 - amp[1:]) / (rho[1:] * (1 - amp[1:])
cs = np.cumprod(np.insert(multipliers, 0, 1450))
(insert
也需要分配一个全新的数组,但没关系,因为我们只分配一次。)
此外,您可能遇到了符号错误。您的公式表示 (amp(i) - 1)
而您的代码表示 (1 - amp[i])
。我已选择匹配您的代码,但您可能需要更正它。
我有一个名为 "cmp_twtt_amp_rho" 的输入文件,它有 7795074 行长。 我想计算每条线的声速 c,其中:
c(i) = rho(i-1) * c(i-1) * (-1-amp(i)) / rho(i) * (amp(i)-1)
使用初始猜测 c=1450。
我写了一个 for 循环,我相信它会起作用,但是它会随着时间的推移变得越来越慢,以至于 运行 在当前格式下是不可想象的。
有人可以帮我加快这段代码的速度吗?
data=np.genfromtxt('./cmp_twtt_amp_rho')
cmp_no=data[:,[0]]
twtt=data[:,[1]]
amp=data[:,[2]]
rho=data[:,[3]]
cs=[]
for i in range(1,len(amp-1)):
if i == 1:
print "Using an initial guess of 1450 m/s"
c = (rho[i-1]*1450*(-1-amp[i]))/(rho[i]*(1-amp[i]))
cs = np.append(c,cs)
elif twtt[i] == 0:
print "Reached new cmp #: ",cmp_no[i],"as twwt has re-started at ",twtt[i]
c = 1450
cs = np.append(c,cs)
else:
print i
c = (rho[i-1]*cs[i-1]*(-1-amp[i]))/(rho[i]*(1-amp[i]))
cs = np.append(c,cs)
print min(cs), max(cs)
print len(cs)
Numpy 数组并不是真的要追加(numpy 需要每次分配一个完整的新数组并将旧数据复制过来)。您可能不想循环执行此操作。
最好使用专为此类事情设计的数据结构——通常 python 的 list
可以很好地处理追加,因此我建议您将数据存储在一个列表并随时附加到它。然后在最后,如果你需要完整的数据集作为数组,你可以在那个时候转换回来。
我建议只更改为 cs.append(c)
而不是 cs = np.append(c, cs)
np.append
必须重新分配整个数组, 不好,但不是唯一的问题。您将 cs
附加到 c
而不是相反,这意味着 cs
将被反转并且 cs[i-1]
实际上是第一个 c
.
通常预分配数组更好:
cs = np.zeros(len(amp-1))
然后直接设置值:
cs[i] = c
像这样应该会快一点:
cs=np.zeros(len(amp-1))
print "Using an initial guess of 1450 m/s"
cs[1] = (rho[i-1]*1450*(-1-amp[i]))/(rho[i]*(1-amp[i]))
for i in range(2,len(amp-1)):
if twtt[i] == 0:
print "Reached new cmp #: ",cmp_no[i],"as twwt has re-started at ",twtt[i]
cs[i] = 1450
else:
print i
cs[i] = (rho[i-1]*cs[i-1]*(-1-amp[i]))/(rho[i]*(1-amp[i]))
追加到数组真的很慢,因为你每次都必须分配一个全新的数组。循环执行几乎总是会降低性能。
无需在循环中追加,甚至根本不使用 Python 级循环,您可以使用向量化运算和累积积更快地完成此操作:
multipliers = rho[:-1] * (-1 - amp[1:]) / (rho[1:] * (1 - amp[1:])
cs = np.cumprod(np.insert(multipliers, 0, 1450))
(insert
也需要分配一个全新的数组,但没关系,因为我们只分配一次。)
此外,您可能遇到了符号错误。您的公式表示 (amp(i) - 1)
而您的代码表示 (1 - amp[i])
。我已选择匹配您的代码,但您可能需要更正它。