2017-09-28 15 views
1

numpy과 함께 다음 문제에 봉착 한 것처럼 보입니다. I를 갖기 때문에, binvals의 값 (및 일부 bins)에있어서, X.shape = (nexp, ntime, ndim, npart) 내가 npart 사이즈에 따라이 배열 비닝 통계를 계산하기 위해 필요하지만,이 다른 모든 치수를 유지 :numpy binned mean, 여분의 축 보존

는 I 모양으로 배열 X을 binned 통계를 사용하여 원본 배열의 일부 바이어스를 제거합니다. Binning 값의 모양은 binvals.shape = (nexp, ntime, npart)입니다.

내가하려는 일을 설명하기위한 완벽한 최소한의 예입니다. 실제로, 나는 큰 배열과 빈의 여러 hunderds 함께 일하고 (그래서이 구현은 영원히 소요) 참고 :

import numpy as np 

np.random.seed(12345) 

X = np.random.randn(24).reshape(1,2,3,4) 
binvals = np.random.randn(8).reshape(1,2,4) 
bins = [-np.inf, 0, np.inf] 
nexp, ntime, ndim, npart = X.shape 

cleanX = np.zeros_like(X) 
for ne in range(nexp): 
    for nt in range(ntime): 
     indices = np.digitize(binvals[ne, nt, :], bins) 
     for nd in range(ndim): 
      for nb in range(1, len(bins)): 
       inds = indices==nb 
       cleanX[ne, nt, nd, inds] = X[ne, nt, nd, inds] - \ 
        np.mean(X[ne, nt, nd, inds], axis = -1) 

가 명확하게 수도의 결과를 보면?

In [8]: X 
Out[8]: 
array([[[[-0.20470766, 0.47894334, -0.51943872, -0.5557303 ], 
     [ 1.96578057, 1.39340583, 0.09290788, 0.28174615], 
     [ 0.76902257, 1.24643474, 1.00718936, -1.29622111]], 

     [[ 0.27499163, 0.22891288, 1.35291684, 0.88642934], 
     [-2.00163731, -0.37184254, 1.66902531, -0.43856974], 
     [-0.53974145, 0.47698501, 3.24894392, -1.02122752]]]]) 

In [10]: cleanX 
Out[10]: 
array([[[[ 0.  , 0.67768523, -0.32069682, -0.35698841], 
     [ 0.  , 0.80405255, -0.49644541, -0.30760713], 
     [ 0.  , 0.92730041, 0.68805503, -1.61535544]], 

     [[ 0.02303938, -0.02303938, 0.23324375, -0.23324375], 
     [-0.81489739, 0.81489739, 1.05379752, -1.05379752], 
     [-0.50836323, 0.50836323, 2.13508572, -2.13508572]]]]) 


In [12]: binvals 
Out[12]: 
array([[[ -5.77087303e-01, 1.24121276e-01, 3.02613562e-01, 
      5.23772068e-01], 
     [ 9.40277775e-04, 1.34380979e+00, -7.13543985e-01, 
      -8.31153539e-01]]]) 

벡터화 된 솔루션이 있습니까? 내가 scipy.stats.binned_statistic을 사용하는 것을 생각했지만,이 목적을 위해 그것을 사용하는 방법을 이해할 수없는 것 같습니다. 감사!

+0

더미 입력을 제공 할 수 있습니까? – norok2

+0

무엇을 의미합니까? 'X = np.random.randn (120) .extape (3,4,2,5)','binvals = np.random.randn (24) .reshape (3,4,2)'그리고 'bins = np.linspace (binvals.min(), binvals.max(), 10)' – user6760680

+0

게시 된 코드의 샘플 데이터와'IndexError : boolean index did not match ..'가 발생했습니다. – Divakar

답변

1

좋아요, 주로 @jdehesa의 대답을 기반으로합니다.

clean2 = np.zeros_like(X) 
d = np.digitize(binvals, bins) 
for i in range(1, len(bins)): 
    m = d == i 
    minds = np.where(m) 
    sl = [*minds[:2], slice(None), minds[2]] 
    msum = m.sum(axis=-1) 
    clean2[sl] = (X - \ 
        (np.sum(X * m[...,np.newaxis,:], axis=-1)/
        msum[..., np.newaxis])[..., np.newaxis])[sl] 

내 원본 코드와 동일한 결과를 제공합니다. 여기 예제의 작은 배열에서는이 솔루션이 원래 코드의 약 3 배 빠릅니다. 나는 그것이 더 큰 배열에서 더 빠를 것이라고 기대한다.

업데이트 : 사실

보다 빠르고 큰 배열에 (공식적인 테스트를하지 않았다)하지만 그럼에도 불구하고, 단지 성능면에서 수용 가능한 수준에 도달 ... 더 제안에 여분의 벡터화는 매우 환영받을 것입니다.

+0

내 대답도 업데이트했습니다. 내 코드는 동일한 결과를 제공하지 않지만 ... 실행하면 제로에 가까운 값을 생성합니다. (원래 포인트 인 것 같아요.) 원래 코드가 최대 +/- 6 값을 생성합니다 (이는 ' X' 값은'[0, 1]'에 있습니다.) ... 나는 차이점을 알지 못합니다! 단지 유용 할 경우를 대비하여 ... – jdehesa

+0

@jdehesa X 값은 표준 정규 분포에서 나온 값이므로 [0,1]로만 제한되지 않습니다. 나는 내 코드를 검사했는데 내가 원했던만큼 빠르지는 않을지라도 내가 필요한 것을 해낸다. 어쨌든 제안에 감사드립니다. 성능을 크게 향상시키는 것은 매우 유용했습니다! – user6760680

2
import numpy as np 

np.random.seed(100) 

nexp = 3 
ntime = 4 
ndim = 5 
npart = 100 
nbins = 4 

binvals = np.random.rand(nexp, ntime, npart) 
X = np.random.rand(nexp, ntime, ndim, npart) 
bins = np.linspace(0, 1, nbins + 1) 

d = np.digitize(binvals, bins)[:, :, np.newaxis, :] 
r = np.arange(1, len(bins)).reshape((-1, 1, 1, 1, 1)) 
m = d[np.newaxis, ...] == r 
counts = np.sum(m, axis=-1, keepdims=True).clip(min=1) 
means = np.sum(X[np.newaxis, ...] * m, axis=-1, keepdims=True)/counts 
cleanX = X - np.choose(d - 1, means) 
+0

글쎄, 나는 그것에 대해 더 생각해야하지만, 실제로 내가 찾던 똑같은 것으로 보이지 않는다. – user6760680

+0

@ user6760680 더 많은 메모리를 소비하면서 루프가없는 대체 솔루션을 추가했습니다 (더 빨라야 함). – jdehesa

+0

나를 설득하지 못했던 것을 이해하는 데는 어느 정도 시간이 걸렸지 만, 중요한 것은 통계를 계산해야하지만 다른 배열을 비닝하는 것입니다. – user6760680