본문 바로가기
데이터 분석/데이터 전처리

[Numpy] 결측치(NaN, missing)를 포함한 두 배열의 상관계수(correlation) 구하기 (with ma.corrcoef)

by 부자 꽁냥이 2022. 5. 12.

안녕하세요?! 꽁냥이입니다. 데이터 분석을 하다 보면 두 배열의 상관 계수를 구할 때가 종종 있지요. 하지만 배열 속에 결측치(NaN, missing)를 포함하고 있다면 상관 계수를 계산할 수 없을 때가 있습니다.

 

예를 들어 아래와 같이 결측치(NaN, missing)를 포함한 두 배열이 있다고 해볼게요.

 

import numpy as np

a = np.array([np.nan, np.nan, 1, 2, 3])
b = np.array([np.nan, np.nan, 10, 14, 16])

 

이 경우 np.nan를 자동적으로 제거하고 [1, 2, 3]과 [10, 14, 16]의 상관계수를 구하고 싶을 것입니다. 하지만 실제로 numpy.corrcoef를 이용하여 상관계수를 구하면 NaN값이 출력됩니다.

 

import numpy as np

a = np.array([np.nan, np.nan, 1, 2, 3])
b = np.array([np.nan, np.nan, 10, 14, 16])

print(np.corrcoef(a, b)[0, 1])

 

nan이 포함된 경우 numpy.corrcoef는 nan을 리턴한다.

 

따라서 이번 포스팅에서는 Numpy를 이용하여 결측치(NaN, missing)를 포함한 배열의 상관 계수를 계산하는 방법에 대해서 알아보겠습니다.

 

여기서 다루는 내용은 다음과 같습니다.

 

1. 결측치(NaN, missing)를 제거하고 상관 계수 구하기

2. Numpy.ma.corrcoef 이용하기


   1. 결측치(NaN, missing)를 제거하고 상관 계수 구하기

이 경우는 두 배열은 같은 길이여야하고 그 속에 포함된 결측치 개수와 위치가 같을 때 사용할 수 있는 방법입니다. 이 방법은 numpy.isnan을 이용하여 nan을 제거한 뒤 상관계수를 구하는 방법입니다.

 

import numpy as np

a = np.array([np.nan, np.nan, 1, 2, 3])
b = np.array([np.nan, np.nan, 10, 14, 16])

# nan을 제거한다
a = [x for x in a if not np.isnan(x)]
b = [x for x in b if not np.isnan(x)]

print(np.corrcoef(a, b)[0, 1])

 

np.isnan을 이용하여 nan을 제거하고 상관계수를 구한다.

주의!!

하지만 이 방법을 사용하면 안되는 2가지 경우가 있습니다. 먼저 길이는 같지만 결측치(NaN, missing) 개수가 다른 경우입니다. 코드를 실행하면 두 배열의 길이가 같아야 한다는 경고를 나타내는 ValueError를 발생시킵니다.

 

import numpy as np

# 두 배열이 포함하는 결측치 개수가 다르다.
a = np.array([np.nan, np.nan, 1, 2, 3]) 
b = np.array([np.nan, 3, 10, 14, 16])

# nan을 제거한다
a = [x for x in a if not np.isnan(x)]
b = [x for x in b if not np.isnan(x)]

print(np.corrcoef(a, b)[0, 1])

 

 

다음으로 두 배열의 길이가 같고 포함된 결측치 개수도 같지만 그 위치가 다른 경우입니다. 이때에는 두 배열 중 어느 하나라도 결측값이 포함된 위치는 제외한 나머지 위치의 배열들을 가지고 상관계수를 구해야 할 것입니다. 하지만 앞선 방법을 사용한다면 예상한 결과와 다르게 나타납니다.

 

import numpy as np

# 두 배열이 포함하는 결측치 개수가 다르다.
a = np.array([np.nan, np.nan, 1, 2, 3]) 
b = np.array([np.nan, 10, np.nan, 14, 16])
# => 우리는 두 배열이 공통 위치의 원소들인 [2, 3], [14, 16]의 상관계수를 구하고 싶다.

# nan을 제거한다
a = [x for x in a if not np.isnan(x)]
b = [x for x in b if not np.isnan(x)]
# => 예상과 달리 [1, 2, 3], [10, 14, 16]의 상관계수를 구하게 된다.
print(np.corrcoef(a, b)[0, 1])

 


   2. Numpy.ma.corrcoef 이용하기

앞에서의 방법은 여러가지 문제가 있다는 것을 알아보았는데요. 앞에서의 장점은 그대로 유지하고 단점까지 해결해주는 방법을 알아보겠습니다. 바로 numpy.ma.corrcoef를 사용하면 되는데요. 사용법은 아래 코드를 보시면 금방 이해되실 거예요.

앞에서와 다른점은 nan을 제거하는 하는 대신 numpy.ma.masked_invalid를 통하여 마스킹 처리를 한 번 해주고 np.corrcoef가 아닌 np.ma.corrcoef를 써야 한다는 것입니다.

 

a = np.array([np.nan, np.nan, 1, 2, 3])
b = np.array([np.nan, np.nan, 10, 14, 16])

a = np.ma.masked_invalid(a) # NaN과 같은 유효하지 않은 값들을 마스크처리
b = np.ma.masked_invalid(b)
print(np.ma.corrcoef(a,b)[0,1])

 

 

numpy.ma.corrcoef를 이용한 상관계수

이 방법은 앞에서 살펴보았던 문제점을 모두 해결해줍니다.

 

import numpy as np

# 두 배열이 포함하는 결측치 개수가 다르다.
a = np.array([np.nan, np.nan, 1, 2, 3]) 
b = np.array([np.nan, 10, np.nan, 14, 16])
# => 우리는 두 배열이 공통 위치의 원소들인 [2, 3], [14, 16]의 상관계수를 구하고 싶다.

a = np.ma.masked_invalid(a) # NaN과 같은 유효하지 않은 값들을 마스크처리
b = np.ma.masked_invalid(b)
# => 우리가 원하는 [2, 3], [14, 16]의 상관계수를 구해준다.
print(np.ma.corrcoef(a, b)[0, 1])

 

numpy.ma.corrcoef 결과


이번 포스팅에서는 Numpy를 이용하여 결측치(NaN, missing)를 포함한 두 배열의 상관계수를 구하는 방법을 알아보았습니다. 보통 데이터 전처리에서 결측치를 제거하거나 대체하기 때문에 결측치를 포함하는 상관계수를 구할 일이 많이 없을 거예요. 하지만 알아두면 예상치 못한 위기에서 큰 힘이 되어줄 겁니다. 지금까지 꽁냥이의 글 읽어주셔서 감사합니다.


댓글


맨 위로