numpy Numba GuFunc输出不正确

pod7payv  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(104)

我有一个python函数如下:

@njit(cache=True, fastmath=True, parallel=True)
    def min_var_opt(covariance_matrix: np.ndarray) -> np.array:
        n = covariance_matrix.shape[0]

        # Compute the inverse of the covariance matrix
        inverse_covariance = np.linalg.inv(covariance_matrix)
    
        ones_vector = np.ones((n, 1))
    
        denominator = np.dot(np.dot(ones_vector.T, inverse_covariance), ones_vector)
    
        weights = np.dot(inverse_covariance, ones_vector) / denominator
        
        return weights
    
    covariance_matrix = np.array(
            [
                [77.25607201, 4.95549419, -2.1582784],
                [4.95549419, 73.87388998, -3.76609601],
                [-2.1582784, -3.76609601, 259.46734795],
            ]
        )
    
    weights = min_var_opt(covariance_matrix).T
    print(f"compiled output:\t{weights}")

字符串
这将产生正确的输出:第一个月
现在,我想将其推广到一系列协方差矩阵上:

@guvectorize([(float64[:, :], float64[:])], "(n, n) -> (n)", nopython=True, cache=True)
    def minimum_variance_optimization(covariance_matrix: np.ndarray, weights: np.array):
        n = covariance_matrix.shape[0]
    
        # Compute the inverse of the covariance matrix
        inverse_covariance = np.linalg.inv(covariance_matrix)
    
        ones_vector = np.ones((n, 1))
    
        denominator = np.dot(np.dot(ones_vector.T, inverse_covariance), ones_vector)
    
        weights = np.dot(inverse_covariance, ones_vector) / denominator
    
    cov = np.array([covariance_matrix])
    vectorized_weights = minimum_variance_optimization(cov)
    print(f"vectorized output once:\t{vectorized_weights}")


这给出了相同的输出vectorized output once: [[0.41740475 0.4411879 0.14140735]]
这是预期的输出。问题似乎是当我应用它与一个以上的内部矩阵。
当我尝试:

cov = np.tile(covariance_matrix, (5, 1, 1))
    vectorized_weights = minimum_variance_optimization(cov)
    print(f"vectorized output repeated:\t{vectorized_weights}")


我得到如下错误输出

vectorized output repeated:[[4.66464261e-310 0.00000000e+000 0.00000000e+000]
    [4.66394411e-310 3.95252517e-323 0.00000000e+000]
    [3.14015482e+179 2.36897524e+261 2.93013167e-002]
    [7.10264216e+083 1.32448107e+007 3.12881791e+011]
    [6.73475158e+107 4.17959458e+025 5.71862049e-310]]


根据this answer,我需要将上面的赋值改为weights[:] = np.dot(inverse_covariance, ones_vector) / denominator以覆盖输入数组,但当我尝试这样做时,numba无法编译,我不明白为什么,但它正在用上面的原始代码编写结果
我期望输出与第一个向量重复5次相同。我一定是错误地调用了gufunc,但我找不到任何与此用例匹配的示例。有人能帮助我了解发生了什么吗?

zzlelutf

zzlelutf1#

你需要对输入数组的第一个维度使用for循环。下面是固定的实现:

@nb.guvectorize([(nb.float64[:, :, :], nb.float64[:, :])], "(k, n, n) -> (k, n)", nopython=True, cache=True)
def minimum_variance_optimization(covariance_matrix: np.ndarray, weights: np.ndarray):
    for k in range(covariance_matrix.shape[0]):
        n = covariance_matrix.shape[1]

        # Compute the inverse of the covariance matrix
        inverse_covariance = np.linalg.inv(covariance_matrix[k, ])

        ones_vector = np.ones((n, 1))

        denominator = np.dot(np.dot(ones_vector.T, inverse_covariance), ones_vector)

        weights[k] = (np.dot(inverse_covariance, ones_vector) / denominator)[:, 0]

字符串
结果如下:

cov = covariance_matrix[np.newaxis, ]
vectorized_weights = minimum_variance_optimization(cov)
print(f"vectorized output once:\t{vectorized_weights}")
vectorized output once: [[0.41740475 0.4411879  0.14140735]]
cov = np.tile(covariance_matrix, (5, 1, 1))
vectorized_weights = minimum_variance_optimization(cov)
print(f"vectorized output repeated:\t{vectorized_weights}")
vectorized output repeated: [[0.41740475 0.4411879  0.14140735]
 [0.41740475 0.4411879  0.14140735]
 [0.41740475 0.4411879  0.14140735]
 [0.41740475 0.4411879  0.14140735]
 [0.41740475 0.4411879  0.14140735]]

相关问题