python - 如何优化这个 NumPy 代码?

标签 python numpy vectorization numeric

以下代码是我的 Python 代码中的瓶颈:

def get_payoff(self,  actual, predicted):
    if abs(actual - 1.0) < 1e-5:  # if actual == 1
        if predicted < 0.5:
            return self.fn_payoff * (0.5 - predicted)
        elif predicted > 0.5:
            return self.tp_payoff * (predicted - 0.5)
        else:
            return 0
    else:
        if predicted < 0.5:
            return self.tn_payoff * (0.5 - predicted)
        elif predicted > 0.5:
            return self.fp_payoff * (predicted - 0.5)
        else:
            return 0

def get_total_payoff(self):
    total_payoff = 0
    for target_element, prediction_element in zip(np.nditer(self.target), np.nditer(predictions)):
        total_payoff += self.get_payoff(target_element, prediction_element)

fn_payoff、tp_payoff、tn_payoff 和 fp_payoff 均为 float 。 self.target 和 self.predictions 都是 numpy ndarray。

我认为有某种方法可以用某种 numpy 向量化替换 get_total_payoff 中的 for 循环,但我不知道如何处理 if/then 语句以正确进行向量化。

最佳答案

向量化根据条件使用不同表达式的函数的关键是使用 np.choose 。另外,在您的情况下, predict-0.50.5-predict 可以替换为 abs(predict-0.5),再加上对predict==0.5 的情况(我猜测特殊处理是为了正确处理 NaN)。

import numpy as np

class A(object):
    def __init__(self):
        self.fn_payoff = 222.
        self.tn_payoff = 444.
        self.fp_payoff = 777.
        self.tp_payoff = 888.
        self.target = np.array([ 0.3, 1., 2. ])
        self.predictions = np.array([ 0.4, 0.5, 1.7 ])

    def get_payoff(self,  actual, predicted):
        if abs(actual - 1.0) < 1e-5:  # if actual == 1
            if predicted < 0.5:
                return self.fn_payoff * (0.5 - predicted)
            elif predicted > 0.5:
                return self.tp_payoff * (predicted - 0.5)
            else:
                return 0
        else:
            if predicted < 0.5:
                return self.tn_payoff * (0.5 - predicted)
            elif predicted > 0.5:
                return self.fp_payoff * (predicted - 0.5)
            else:
                return 0

    def get_total_payoff(self):
        total_payoff = 0
        for target_element, prediction_element in zip(np.nditer(self.target), np.nditer(self.predictions)):
            total_payoff += self.get_payoff(target_element, prediction_element)
        return total_payoff

    def get_total_payoff_VECTORIZED(self):
        actual_mask = np.abs(self.target - 1) < 1e-5
        predict_mask = self.predictions < 0.5
        payoff_n = np.choose(actual_mask, [ self.tn_payoff, self.fn_payoff ])
        payoff_p = np.choose(actual_mask, [ self.fp_payoff, self.tp_payoff ])
        payoff = np.choose(predict_mask, [ payoff_p, payoff_n ]) * abs(self.predictions-0.5)
        payoff[self.predictions==0.5] = 0
        return payoff.sum()

a = A()
print a.get_total_payoff()
=> 976.8
print a.get_total_payoff_VECTORIZED()
=> 976.8

关于python - 如何优化这个 NumPy 代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21766307/

相关文章:

arrays - 在 Numpy 中旋转图像数组

c - openmp simd 失败

python - 快速查找集合中的 numpy 向量

python - Cassandra 关于 CQLENG_ALLOW_SCHEMA_MANAGEMENT 的警告

python - subprocess.run() 产生与手动输入不同的结果

python - Numpy:根据密度函数生成网格

python - numpy中这些数组形状之间的区别

python - 高效处理 Python 列表中的重复项

r - 如何在 r 中编写函数来对记录进行计算?

python - 如何将参数(对于 FEED_URI)传递给 Scrapy 蜘蛛的实例以动态命名输出文件