【问题标题】:Fast method to dispatch computation according to tests in a function with array as argument根据以数组为参数的函数中的测试来调度计算的快速方法
【发布时间】:2021-01-11 10:59:29
【问题描述】:

这是我正在处理的 Numpy 中的一个简化用例,如何调度一些计算?

def f(x,th1=0.25,th2=0.75):
if x < th1:
    return x+10
elif x > th2:
    return x+30
else:
    return x+20

x 是一个 Numpy 向量

x=np.random.uniform(0,1,10**6)

当然,如果我尝试f(x),我会得到预期的结果

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

现在我可以使用一个简单的循环了:

%%timeit
 tmp=[]
 for i in range(x.shape[0]):
    tmp.append(f(x[i]))
 np.array(tmp)

我收到873 ms ± 8.98 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

我也可以使用np.vectorize

fvec=np.vectorize(f)

%%timeit
fvec(x)

248 ms ± 2.45 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

但我很确定有人可以使用“面具”来真正提升,或者可能是另一种 numpy 技巧。所以,轮到你了……提前致谢。

【问题讨论】:

    标签: python performance numpy


    【解决方案1】:

    您可以使用np.where 来执行此操作-

    def f(x):
        y = np.where(x<0.25, x+10, x)
        y = np.where(x>0.75, y+30, y)
        y = np.where(np.bitwise_and(0.25<=x, x<=0.75), y+20, y)
        return y
    

    在我的系统上,它在18ms 中运行。

    x = np.random.uniform(0,1,10**6)
    %timeit t = f(x)
    

    18 ms ± 86.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)中运行

    同时

    fvec=np.vectorize(f2)
    %timeit fvec(x)
    

    其中 f2 是您定义的在 185 ms ± 2.81 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) 上运行的函数

    【讨论】:

    • 没有必要使用比裸条件慢的np.where
    【解决方案2】:

    您可以使用以下方法:

    def fff(x,th1=0.25,th2=0.75):
        plus20 = x >= th1
        plus30 = x <= th2
        x[plus20] += 10
        x[plus30] += 10
        return x + 10
    

    时间(这个):

    %%timeit
    fff(x)
    
    7.59 ms ± 177 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    

    时间(你的):

    %%timeit
    fvec(x)
    
    201 ms ± 7.22 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    【讨论】:

      【解决方案3】:

      你可以这样做:

      def f(x,th1=0.25,th2=0.75):
          return x + 20 - 10*(x<th1) + 10*(x>th2)
      

      这将允许您使用 y = f(x) 而不会对 x 产生副作用(因为 sophros 的解决方案会导致)。

      如果您的值比 10,20,30 更复杂,您可以使用乘数作为映射数组的索引而不是值本身来概括该方法:

      mapping = np.array([20,10,30])
      def f(x,th1=0.25,th2=0.75):
          return x + mapping[1*(x<th1) + 2*(x>th2)]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-20
        • 1970-01-01
        • 2011-03-04
        • 2020-07-07
        • 1970-01-01
        • 2015-01-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多