使用numpy数组输入的Python函数给出了意外的结果

2024-06-25 06:43:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我的程序中有一个函数可以计算出相关系数。它需要两个平面(一维)numpy数组,并对它们执行必要的计算,以计算出两个数字列表(它们是货币,属于float类型)之间的相关性。只要程序运行,这个函数每个循环执行136次,每个循环大约需要0.05秒。以下代码按预期计算系数:

def CC(a, b):
    a = a - np.mean(a)
    b = b - np.mean(b)
    ab = np.sum(a*b)
    asq = np.sum(a**2)
    bsq = np.sum(b**2)
    cc = round(ab / sqrt(asq * bsq), 5)
    return cc

但是它最终会导致内存泄漏。解决此内存泄漏的方法是将函数更改为:

def CC(a, b):
    cc = round(np.sum((a - np.mean(a)) * (b - np.mean(b))) / sqrt(np.sum(a**2) * np.sum(b**2)), 5)
    return cc

它只在一行中完成,并且不创建任何新的列表,因此节省了内存并避免了泄漏。你知道吗

然而,由于一些奇怪的原因,当使用方法2时,返回值从0.1开始,然后在大约20秒的时间内下降到0,然后从那时起保持在0。每次都是这样。我也尝试过方法2的替代方法,即1或2个额外的计算步骤-同样的结果。我已经通过消除过程隔离了所有可能的错误源,所有这些都归结为函数本身内部发生的事情,所以这肯定是个问题。到底是什么原因造成的?就好像CC函数忽略了它给出的输入。。。如果是以某种方式设置的。。?你知道吗


Tags: 方法函数内存列表abdefnpsqrt
1条回答
网友
1楼 · 发布于 2024-06-25 06:43:12

您的代码不相等,第一个代码在第一步中重新分配ab

a = a - np.mean(a)
b = b - np.mean(b)

所有后续操作都使用更新的ab。然而,您的第二种方法只是在sqrt术语中忽略了这些:

sqrt(np.sum(a**2) * np.sum(b**2))

应与以下内容相同:

sqrt(np.sum((a-a.mean())**2) * np.sum((b-b.mean())**2))

一些补充意见:

Which works it all out in one line and doesn't create any new lists, hence saving memory.

这不是真的(至少不总是这样),它仍然会产生新的数组。但我可以看到两个可以避免创建中间数组的地方:

np.subtract(a, a.mean(), out=a)  
# instead of "a = a - np.mean(a)"
# possible also "a -= a" should work without temporary array, but I'm not 100% sure.

同样适用于b = b - np.mean(b)

However it eventually results in a memory leak.

我在第一个函数中找不到任何内存泄漏的证据。你知道吗


如果您关心中间数组,您可以自己进行操作。我用来显示它,但是这可以很容易地移植到或类似的地方(但是我不需要添加类型注释):

import numpy as np
import numba as nb
from math import sqrt

@nb.njit
def CC_helper(a, b):
    sum_ab = 0.
    sum_aa = 0.
    sum_bb = 0.
    for idx in range(a.size):
        sum_ab += a[idx] * b[idx]
        sum_aa += a[idx] * a[idx]
        sum_bb += b[idx] * b[idx]
    return sum_ab / sqrt(sum_aa * sum_bb)

def CC1(a, b):
    np.subtract(a, a.mean(), out=a) 
    np.subtract(b, b.mean(), out=b)
    res = CC_helper(a, b)
    return round(res, 5)

并将性能与您的两个功能进行了比较:

def CC2(a, b):
    a = a - np.mean(a)
    b = b - np.mean(b)
    ab = np.sum(a*b)
    asq = np.sum(a**2)
    bsq = np.sum(b**2)
    cc = round(ab / sqrt(asq * bsq), 5)
    return cc

def CC3(a, b):
    cc = round(np.sum((a - np.mean(a)) * (b - np.mean(b))) / sqrt(np.sum((a - np.mean(a))**2) * np.sum((b - np.mean(b))**2)), 5)
    return cc

并确保结果一致,然后计时:

a = np.random.random(100000)
b = np.random.random(100000)

assert CC1(arr1, arr2) == CC2(arr1, arr2)
assert CC1(arr1, arr2) == CC3(arr1, arr2)

%timeit CC1(arr1, arr2)  # 100 loops, best of 3: 2.06 ms per loop
%timeit CC2(arr1, arr2)  # 100 loops, best of 3: 5.98 ms per loop
%timeit CC3(arr1, arr2)  # 100 loops, best of 3: 7.98 ms per loop

相关问题 更多 >