[Python] Numpy - 상관계수 메트릭스에서 중복되지 않은 값으로 1차원 벡터 생성 (Upper triangular part of correlation coefficient matrix)
예시를 위해 NumPy를 임포트 하고, 다음과 같은 random array를 이용하여 상관계수 메트릭스를 생성해 주었다.
import numpy as np
>>> sample = np.random.rand(4, 5)
>>> sample
array([[0.77392506, 0.09906371, 0.93374673, 0.47835984, 0.74820074],
[0.58517649, 0.54654451, 0.68912933, 0.85703762, 0.09354503],
[0.59461011, 0.23737879, 0.051128 , 0.33242827, 0.7303699 ],
[0.30040008, 0.10771157, 0.31072352, 0.92200922, 0.05826817]])
>>> sample_corr = np.corrcoef(sample)
>>> sample_corr
array([[ 1. , -0.13656917, 0.15745992, -0.02845391],
[-0.13656917, 1. , -0.68328825, 0.77288393],
[ 0.15745992, -0.68328825, 1. , -0.24453492],
[-0.02845391, 0.77288393, -0.24453492, 1. ]])
마스크를 생성하기 위해서 np.tri()함수를 활용하려고 한다. numpy.tri()함수는 다음과 같은 파라미터를 갖는다.
(https://numpy.org/doc/stable/reference/generated/numpy.tri.html)
numpy.tri(N, M=None, k=0, dtype=<class 'float'>, *, like=None)
- N: 생성할 array의 row(행) 개수 (int)
- M: 생성할 array의 column(열) 개수 (int)
optional이며, 값이 주어지지 않는 경우 row개수인 N값과 같은 값이 디폴트로 쓰임 - k: optional, int
triangle파트의 범위를 지정해 주는 파라미터로 디폴트 값은 0이고
array의 왼쪽 아래 부터 대각선 요소의 값까지를 포함
(k<0는 대각선 요소보다 아래쪽의 값까지, k>0는 대각선 요소보다 위쪽의 값까지 범위를 의미)
아래쪽에서 조금 더 자세히 살펴볼 예정 - dtype: dtype, optional
디폴트 값은 float으로 array 요소의 데이터 타입을 설정해 줄 수 있음
ex) boolean etc. - like: array_like
NumPy array가 아닌 array의 생성을 허용
아래의 예시와 같이 현재 samle_corr이라는 변수에 저장된 array의 shape이 (4x4)이므로 np.tri()함수를 이용하여 4x4 array를 만들어 주었다. array를 메트릭스로 보았을 때, k=0이면 메트릭스의 가장 왼쪽 아래 성분부터 대각 성분 까지 1, 그 외는 0으로 구성되어 있음을 알 수 있다. dtype을 bool로 설정하였을 때는 0과 1 대신 False 와 True로 출력된다.
>>> np.tri(sample_corr.shape[0], k=0)
array([[1., 0., 0., 0.],
[1., 1., 0., 0.],
[1., 1., 1., 0.],
[1., 1., 1., 1.]])
>>> np.tri(sample_corr.shape[0], k=0, dtype=bool)
array([[ True, False, False, False],
[ True, True, False, False],
[ True, True, True, False],
[ True, True, True, True]])
k값을 변경해 주었을 때의 예시.
k=0과 대각선 성분을 기준으로 k의 값이 1씩 줄었을 때는 1 (True)로 선택된 부분이 1칸씩 줄어들고, 1씩 늘어나는 경우에는 대각선 성분 위쪽 부분으로 한 칸씩 늘어나는 것을 볼 수 있다.
>>> np.tri(sample_corr.shape[0], k=0)
array([[1., 0., 0., 0.],
[1., 1., 0., 0.],
[1., 1., 1., 0.],
[1., 1., 1., 1.]])
>>> np.tri(sample_corr.shape[0], k=-1)
array([[0., 0., 0., 0.],
[1., 0., 0., 0.],
[1., 1., 0., 0.],
[1., 1., 1., 0.]])
>>> np.tri(sample_corr.shape[0], k=1)
array([[1., 1., 0., 0.],
[1., 1., 1., 0.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
>>> np.tri(sample_corr.shape[0], k=2)
array([[1., 1., 1., 0.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
마스크에서 False값을 가진 요소와 같은 위치에 있는 요소들의 값만 sample_corr array에서 가지고 오기 위해 k=0인 np.tri()함수를 이용하여 array를 생성하고 np.ma.masked_where()함수를 이용하여 마스크를 생성해 주었다. (m이라는 변수에 마스크 저장)
>>> mask = np.tri(sample.shape[0], k=0)
>>> mask
array([[1., 0., 0., 0.],
[1., 1., 0., 0.],
[1., 1., 1., 0.],
[1., 1., 1., 1.]])
>>> m = np.ma.masked_where(mask == 1, mask)
>>> m
masked_array(
data=[[--, 0.0, 0.0, 0.0],
[--, --, 0.0, 0.0],
[--, --, --, 0.0],
[--, --, --, --]],
mask=[[ True, False, False, False],
[ True, True, False, False],
[ True, True, True, False],
[ True, True, True, True]],
fill_value=1e+20)
이제 np.ma.masked_where( 마스크, 데이터를 가져오고 싶은 array ).compress() 와 같이 입력했을 때, sample_corr의 메트릭스에서 upper triangular part의 값들만 추출한 1차원 array가 출력된다.
>>> np.ma.masked_where(m, sample_corr).compressed()
array([-0.13656917, 0.15745992, -0.02845391, -0.68328825, 0.77288393, -0.24453492])
>>> sample_corr
array([[ 1. , -0.13656917, 0.15745992, -0.02845391],
[-0.13656917, 1. , -0.68328825, 0.77288393],
[ 0.15745992, -0.68328825, 1. , -0.24453492],
[-0.02845391, 0.77288393, -0.24453492, 1. ]])