복붙노트

[PYTHON] 상관 행렬 찾기

PYTHON

상관 행렬 찾기

상당히 큰 행 (약 50K 행)을 가지고 있고, 행렬의 각 행 사이에 상관 계수를 인쇄하려고합니다. 필자는 다음과 같이 Python 코드를 작성했습니다.

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 함수를 사용하고 있습니다.

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

감사!

해결법

  1. ==============================

    1.새로운 솔루션

    새로운 솔루션

    Joe Kington의 대답을보고 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에서 계산됩니다. 또한 p- 값 (pearsonr ()도 반환 함)을 사용하지 않으므로이 값도 사용하십시오. 아래 코드를 사용하십시오.

    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)
    

    p 값의 물건을 제거했을 때 직선 scipy 코드보다 약 4.8 배 빠릅니다. p 값 물건을 남겨두면 8.8x (수백 개의 열이있는 10 개의 열을 사용했습니다). 나는 또한 그것이 동일한 결과를주는 것을 확인했다. 이것은 큰 개선이 아니지만 도움이 될 수 있습니다.

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

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

  2. ==============================

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

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

    무작위 데이터의 결과를 신속하게 확인하기 만하면 위의 @Justin Peel 코드와 똑같은 것을 반환하고 ~ 100x 빠릅니다.

    예를 들어, 1000 개의 행과 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는 사용자가 원하는 것을 수행해야하며 훨씬 빠릅니다.

  3. ==============================

    3.당신은 파이썬 다중 프로세스 모듈을 사용할 수 있습니다, 10 세트로 행을 청크, 결과를 버퍼링하고 물건을 출력 (이것은 멀티 코어 기계에서만 속도를 높일 것입니다)

    당신은 파이썬 다중 프로세스 모듈을 사용할 수 있습니다, 10 세트로 행을 청크, 결과를 버퍼링하고 물건을 출력 (이것은 멀티 코어 기계에서만 속도를 높일 것입니다)

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

    btw : 스 니펫을 함수로 변환하고 데이터 재구성을 수행하는 방법도 고려해야합니다. 각각의 하위 프로세스에 이런 목록이 있습니다 ... [startcord, stopcord, buff] .. 잘 작동 할 수 있습니다.

    def myfunc(thelist):
        for i in xrange(thelist[0]:thelist[1]):
        ....
        thelist[2] = result
    
  4. from https://stackoverflow.com/questions/3437513/finding-the-correlation-matrix by cc-by-sa and MIT license