@@ -345,8 +345,8 @@ def nancorr(const float64_t[:, :] mat, bint cov=False, minp=None):
345345 float64_t[:, ::1 ] result
346346 uint8_t[:, :] mask
347347 int64_t nobs = 0
348- float64_t xx, xy , meanx, meany, divisor, number, v1sq, v2sq , val
349- float64_t* vx, vy
348+ float64_t vx, vy , meanx, meany, divisor, ssqdmx, ssqdmy, cxy , val
349+ float64_t sumx, sumy
350350
351351 N, K = (< object > mat).shape
352352 if minp is None :
@@ -358,55 +358,43 @@ def nancorr(const float64_t[:, :] mat, bint cov=False, minp=None):
358358 mask = np.isfinite(mat).view(np.uint8)
359359
360360 with nogil:
361- # for xi in range(K):
362- # for yi in range(xi + 1):
361+ for xi in range (K):
362+ for yi in range (xi+ 1 ):
363363 # Welford's method for the variance-calculation
364364 # https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
365- nobs = v1sq = v2sq = covxy = meanx = meany = 0
366- for i in range (N):
367- vx = ptr(mat[i,:])
368- vy = mat[i,:]
369- meanx = vx.mean()
370- meany = vy.mean()
371- for j in range (vx):
372- xx = (vx[j]- meanx)
373- yy = (vy[j]- meany)
374- nobs += 1
375- number += xx* yy
376- v1sq += xx* xx
377- v2sq += yy* yy
378- val = number/ sqrt(v1sq * v2sq)
379- print (val)
380-
381- # for i in range(N):
382- # if mask[i, xi] and mask[i, yi]:
383- # vx = mat[i, xi]
384- # vy = mat[i, yi]
385- # nobs += 1
386- # dx = vx - meanx
387- # dy = vy - meany
388- # meanx += 1. / nobs * dx
389- # meany += 1. / nobs * dy
390- # ssqdmx += (vx - meanx) * dx
391- # ssqdmy += (vy - meany) * dy
392- # covxy += (vx - meanx) * dy
393-
394- # if nobs < minpv:
395- # result[xi, yi] = result[yi, xi] = NaN
396- # else:esult[xi, yi] = result[yi, xi] = val
397- # divisor = (nobs - 1.0) if cov else sqrt(ssqdmx * ssqdmy)
398-
399- # # clip `covxy / divisor` to ensure coeff is within bounds
400- # if divisor != 0:
401- # val = covxy / divisor
402- # if not cov:
403- # if val > 1.0:
404- # val = 1.0
405- # elif val < -1.0:
406- # val = -1.0
407- # result[xi, yi] = result[yi, xi] = val
408- # else:
409- # result[xi, yi] = result[yi, xi] = NaN
365+ # Changed to Welford's two-pass for improved numeric stability
366+ nobs = ssqdmx = ssqdmy = cxy = meanx = meany = 0
367+ sumx = sumy = 0
368+ for i in range (N):
369+ if mask[i, xi] and mask[i, yi]:
370+ sumx += mat[i, xi]
371+ sumy += mat[i, yi]
372+ nobs += 1
373+ if nobs < minpv:
374+ result[xi, yi] = result[yi, xi] = NaN
375+ continue
376+ meanx = sumx / nobs
377+ meany = sumy / nobs
378+ for i in range (N):
379+ if mask[i, xi] and mask[i, yi]:
380+ vx = mat[i, xi] - meanx
381+ vy = mat[i, yi] - meany
382+ cxy += vx * vy
383+ ssqdmx += vx * vx
384+ ssqdmy += vy * vy
385+ divisor = (nobs - 1.0 ) if cov else sqrt(ssqdmx * ssqdmy)
386+
387+ # clip `covxy / divisor` to ensure coeff is within bounds
388+ if divisor != 0 :
389+ val = cxy / divisor
390+ if not cov:
391+ if val > 1.0 :
392+ val = 1.0
393+ elif val < - 1.0 :
394+ val = - 1.0
395+ result[xi, yi] = result[yi, xi] = val
396+ else :
397+ result[xi, yi] = result[yi, xi] = NaN
410398
411399 return result.base
412400
0 commit comments