【问题标题】:Optimising iterative loop优化迭代循环
【发布时间】:2013-05-29 22:20:46
【问题描述】:

我正在逐渐从 Matlab 转向 Python,并希望获得一些关于优化迭代循环的建议。 这就是我当前运行循环的方式,并且我已经包含了定义变量的代码。

nh = 2000 
h = np.array(range(nh))
nt = 10000 
wmin = 1 
wmax = 10
hw = np.array(wmin + (wmax-wmin)*invlogit(randn(1,nh))); 
sl = np.array(zeros((nh,1))+radians(40))
fa = np.array(zeros((nh,1))+radians(35))
c = np.array(zeros((nh,1))+4.4)
y = np.array(zeros((nh,1))+17.6)
yw = np.array(zeros((nh,1))+9.81)
ir = 0.028
m = np.array(zeros((nh,nt)));
m[:,49] = 0.1
z = np.array(zeros((nh,nt)))
z[:,0] = 0+(3.0773-0)*rand(nh,1).T
reset = np.array(zeros((nh,nt)))
fs = np.array(zeros((nh,nt)))

for t in xrange(0, nt-1):
    fs[:,t] = (c.T+(y.T-m[:,t]*yw.T)*z[:,t]*(np.cos(sl.T)**2)*np.tan(fa.T))/(y.T*z[:,t]*np.sin(sl.T)*np.cos(sl.T))
    reset[fs[:,t]<=1,t+1] = 1;
    z[fs[:,t]<=1,t+1] = 0;
    z[fs[:,t]>1,t+1] = z[fs[:,t]>1,t]+(ir/hw[0,fs[:,t]>1]).T

这就是我在 Matlab 中优化代码的方式,但是它在 python 中运行得相当慢。我怀疑有一种更 Pythonic 的方式可以做到这一点,并且非常感谢朝着正确的方向轻推。 非常感谢!

【问题讨论】:

  • 有没有办法让您确定循环中的 4 个操作中哪一个花费的时间最多?这可能有助于我们确定最需要帮助的地方(我可能猜想这是第一个......三角函数非常慢)。
  • 我还注意到,您对数组的索引方式比 C 存储更适合 Fortran 存储。您可能会考虑让 numpy 以 Fortran 顺序存储您的数组。
  • 感谢 Seth,Fortran 订单加快了速度。对于信息/示例,可以使用 z = np.zeros((nh,nt), order='F')

标签: python matlab loops numpy iteration


【解决方案1】:

表达式

(c.T+(y.T-m[:,t]*yw.T)*z[:,t]*(np.cos(sl.T)**2)*np.tan(fa.T))/(y.T*z[:,t]*np.sin(sl.T)*np.cos(sl.T))

使用不会在循环内更改的c, y, m, yw, sl, fa。您可以在循环之前计算几个子表达式。

此外,这些数组中的大多数都包含一个重复值。您可以改为使用标量进行计算:

sl = radians(40)
fa = radians(35)
c = 4.4
y = 17.6
yw = 9.81

然后,使用预先计算的子表达式:

A = cos(sl)**2 * tan(fa) * (y - m*yw)
B = y*sin(sl)*cos(sl)

for t in xrange(0, nt-1):
    fs[:,t] = (c + A[:,t]*z[:,t]) / (B*z[:,t])
    less = fs[:,t]<=1
    more = np.logical_not(less)
    reset[less,t+1] = 1
    z[less,t+1] = 0
    z[more,t+1] = z[more,t]+(ir/hw[0,more]).T

【讨论】:

    【解决方案2】:

    不是专门关于循环的,你在调用中做了很多额外的工作,看起来像:

    np.array(zeros((nh,nt)))
    

    只需使用:

    np.zeros((nh,nt))
    

    在它的位置。此外,您可以替换:

    h = np.array(range(nh))
    

    与:

    h = np.arange(nh)
    

    其他cmets:

    • 您在每个循环中都调用np.sin(sl.T)*np.cos(sl.T),尽管sl 似乎根本没有改变。只需计算一次并将其分配给您在循环中使用的变量。您可以在一堆触发调用中执行此操作。

    【讨论】:

    • 谢谢 Josh,我现在已经在循环之前分配了触发器并整理了数组定义。速度略有提高,看起来更整洁。干杯
    • 看看 numpy 广播规则的文档也是值得的。
    猜你喜欢
    • 2010-10-22
    • 2016-12-25
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    • 1970-01-01
    • 2011-10-12
    相关资源
    最近更新 更多