2010-08-09 7 views
11

상당히 큰 (약 50K 행) 행렬이 있고 행렬의 각 행 사이에 상관 계수를 인쇄하려고합니다. 나는이 같은 파이썬 코드를 작성했습니다 :상관 행렬 찾기

for i in xrange(rows): # rows are the number of rows in the matrix. 
    for j in xrange(i, rows): 
     r = scipy.stats.pearsonr(data[i,:], data[j,:]) 
     print r 

내가 scipy 모듈 (http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.pearsonr.html)에서 사용할 수있는 pearsonr 기능을 활용하고 있습니다.

내 질문은 : 더 빠른 방법이 있습니까? 사용할 수있는 일부 매트릭스 파티션 기술이 있습니까?

감사합니다.

답변

0

당신은

http://docs.python.org/library/multiprocessing.html

(이것은 단지 비록 멀티 코어 머신에 속도를 높일 것), 10 개 세트로 파이썬 멀티 프로세스 모듈, 덩어리까지 당신의 행을 사용하여 결과를 버퍼링 한 후 물건을 인쇄 할 수 있습니다

btw : 스 니펫을 함수로 변환하고 데이터 재구성을 수행하는 방법도 고려해야합니다. 각 하위 프로세스는이 같은 목록이 한 가지는 ... [startcord이 stopcord, 버프는] ... 조 킹톤의 대답을보고 한 후 잘

def myfunc(thelist): 
    for i in xrange(thelist[0]:thelist[1]): 
    .... 
    thelist[2] = result 
+0

나는 여기서 무엇을 의미하는지에 대한보다 철저한 예를보고 싶습니다. – vgoklani

+0

내 대답은이 시점에서이 질문에서 멀리 떨어져 있다고 생각하지만 다중 처리에 관심이있는 경우 http://docs.python.org/library/multiprocessing.html ... 본질적으로 행을 순환하는 대신 체크 아웃하십시오. , 당신은 함수와 쓰레드 풀을 만들고 그냥 p.map (myfunc, xrange (rows)) – pyInTheSky

10

새로운 솔루션

를 작동 할 수 있습니다, 나는 조사하기로 결정 corrcoef() 코드를 사용했으며 다음 구현을 수행하는 데 영감을 받았습니다.

ms = data.mean(axis=1)[(slice(None,None,None),None)] 
datam = data - ms 
datass = np.sqrt(scipy.stats.ss(datam,axis=1)) 
for i in xrange(rows): 
    temp = np.dot(datam[i:],datam[i].T) 
    rs = temp/(datass[i:]*datass[i]) 

통해 각 루프는 I 및 I 행 내지 마지막 행의 행 사이의 피어슨 계수를 생성한다. 그것은 매우 빠릅니다. 계수와 다른 몇 가지 사항을 중복 계산하지 않기 때문에 적어도 corrcoef()을 사용하는 것보다 1.5 배 빠릅니다. 또한 더 빠를 것이며 50,000 행 행렬에 대한 메모리 문제를주지 않을 것입니다. 그 이유는 각각의 r 세트를 저장하거나 다른 세트를 생성하기 전에이를 처리 할 수 ​​있기 때문입니다. r의 장기간의 데이터를 저장하지 않고, 꽤 새로운 노트북에서 분당 50,000 x 10 세트의 무작위로 생성 된 데이터에서 위의 코드를 실행할 수있었습니다.

올드 솔루션

첫째, 나는 화면에 R의를 인쇄하는 것을 권장하지 않습니다. 100 행 (10 열)의 경우 인쇄시 19.79 초와 코드를 사용하지 않은 경우 0.301 초 사이의 차이입니다. 그냥 r을 저장하고 나중에 원하면 사용하거나, 가장 큰 r을 찾는 것처럼 진행하면서 처리하십시오.

둘째, 일부 수량을 중복 계산하지 않아도 비용을 절약 할 수 있습니다. Pearson 계수는 행이 사용될 때마다 계산하지 않고 미리 계산할 수있는 일부 수량을 사용하여 scipy에서 계산됩니다. 내가 직선 scipy을 통해 약 4.8 배의 속도 향상을 얻을

r = np.zeros((rows,rows)) 
ms = data.mean(axis=1) 

datam = np.zeros_like(data) 
for i in xrange(rows): 
    datam[i] = data[i] - ms[i] 
datass = scipy.stats.ss(datam,axis=1) 
for i in xrange(rows): 
    for j in xrange(i,rows): 
     r_num = np.add.reduce(datam[i]*datam[j]) 
     r_den = np.sqrt(datass[i]*datass[j]) 
     r[i,j] = min((r_num/r_den), 1.0) 

:. 또한, 아래의 코드를 사용하여 너무 그래서 스크래치하자도 pearsonr()에 의해 반환되는 p- 값을 (사용하지 않는 P- 값 물건을 제거했을 때 코드 - 8.8 배로 P 값 물건을 남겨두면 (나는 수백 개의 열이있는 10 개의 열을 사용했다.) 또한 같은 결과를 얻는 지 확인했다. 정말 큰 개선이지만 도움이 될 것입니다.

궁극적으로, (50000) * (50001)/2 = 1,250,025,000의 피어슨 계수를 계산하는 문제에 봉착했습니다 (정확하게 계산하는 경우). 그게 많이 있습니다. 그런데 실제로는 각 행의 Pearson 계수를 계산할 필요가 없습니다 (1과 같음). 그러나 피어슨 계수를 계산하면 5 만원을 절약 할 수 있습니다. 위의 코드를 사용하면 소규모 데이터 집합의 결과를 기반으로 데이터에 10 개의 열이있는 경우 계산을 수행하는 데 약 4 시간이 걸릴 것으로 예상됩니다.

위의 코드를 Cython 또는 유사한 것으로 가져 가면 약간의 개선 효과를 얻을 수 있습니다. 운이 좋다면 곧장 Scipy보다 10 배 향상 될 것으로 기대합니다. 또한 pyInTheSky에서 제안한 것처럼 멀티 프로세싱을 할 수 있습니다.

6

numpy.corrcoef을 사용해 보셨습니까? 어떻게하면 p 값을 사용하지 않는지 알 수 있으므로 원하는대로 정확하게 수행 할 수 있습니다. (정확히 pearson의 R이 무엇인지 정확히 기억하지 못한다면.)

임의의 데이터에 대한 결과를 바로 확인하면, 위의 @Justin Peel의 코드와 정확히 똑같은 것을 반환하고 ~ 100x 빠르게 실행됩니다 . 1,000 행과 랜덤 데이터의 10 열 것을 시험 예

는 ... :

import numpy as np 
import scipy as sp 
import scipy.stats 

def main(): 
    data = np.random.random((1000, 10)) 
    x = corrcoef_test(data) 
    y = justin_peel_test(data) 
    print 'Maximum difference between the two results:', np.abs((x-y)).max() 
    return data 

def corrcoef_test(data): 
    """Just using numpy's built-in function""" 
    return np.corrcoef(data) 

def justin_peel_test(data): 
    """Justin Peel's suggestion above""" 
    rows = data.shape[0] 

    r = np.zeros((rows,rows)) 
    ms = data.mean(axis=1) 

    datam = np.zeros_like(data) 
    for i in xrange(rows): 
     datam[i] = data[i] - ms[i] 
    datass = sp.stats.ss(datam,axis=1) 
    for i in xrange(rows): 
     for j in xrange(i,rows): 
      r_num = np.add.reduce(datam[i]*datam[j]) 
      r_den = np.sqrt(datass[i]*datass[j]) 
      r[i,j] = min((r_num/r_den), 1.0) 
      r[j,i] = r[i,j] 
    return r 

data = main() 

는 최대 절대 차를 산출 ~ 3.3e-16 개의 결과

그리고 타이밍 사이 :

In [44]: %timeit corrcoef_test(data) 
10 loops, best of 3: 71.7 ms per loop 

In [45]: %timeit justin_peel_test(data) 
1 loops, best of 3: 6.5 s per loop 

numpy.corrcoef은 원하는대로 수행해야합니다.

+0

당신은 맞습니다. 나는 처음에는 'corrcoef'를 생각했지만, 느린 것을 기억하는 몇 가지 이유가있었습니다. 나는 양심의 가책을 느껴서 그것을 시험하기보다는 나의 나쁜 기억을 믿었다. 파이썬 루프를 제거하기 위해 행렬 곱셈을 사용하기 때문에 더 빠릅니다. +1. –

+0

그러나 corrcoef의 문제점은 필요에 따라 약 두 배의 메모리를 사용한다는 것입니다. 또한 거의 모든 계수를 두 번 계산합니다. 그러나 더 큰 문제는 메모리이며 OP는 메모리 문제를 피하기 위해 데이터를 분리해야합니다. 그것은 본질적으로 조합론의 혼란이 될 것입니다. –

+0

@Justin Peel - 사실, corrcoef는 입력 배열의 여분의 임시 복사본을 만듭니다. 속도와 사용 된 메모리 양 사이의 절충안입니다. 메모리가 주요 제약 조건이고 50,000 개의 행이있는 경우 솔루션이 훨씬 뛰어납니다. –