본문 바로가기

카테고리 없음

numpy를 활용한 quantiletransformer

728x90
반응형

1. 개요

주어진 스칼라 값들의 분포로부터 새로운 값이 들어왔을 때 이것이 몇 분위의 값을 갖는지 알고 싶을 때가 있다.

예를들어, [1,......,1000] 이라는 값이 있다면 50.5라는 값은 여기서 몇 분위의 값인지 알고 싶은 것이다.
scikt-learn에는 sklearn.preprocessing.QuantileTransformer라는 기능은 이를 위한 기능을 제공하지만 버전이 업그레이드 됨에 따라 문제가 생기기 쉽다.

이를 방지하기 위해 numpy array 기능으로 만든 것을 만들어봤다.

 

2. 코드

class quantiletransformer:
    '''
    numpy array를 활용해서 주어진 값에 대한 quantile transformation을 하는 기능
    fit : 주어진 훈련 데이터에 대해 균등한 분포로 quantile값을 추출함.
    이후 해당 분포의 최소값과 최대값 샘플을 1개 씩 추출함.
    샘플들 간에는 중복값은 존재하지 않게 만듬.
    '''
    import numpy as np
    def __init__(self,n_subsample=1000,decimals=3):
        self.n_subsample=n_subsample
        self.reference_values=np.array([])
        self.quantiles=np.linspace(0,1,n_subsample) # quantile을 생성함 0.001,.....0.999,1.000
        self.decimals=decimals # 참조값의 소수 몇 번째 자리까지 인정할지를 결정함.
    def fit(self,x):
        '''
        x : 1차원 벡터 numpy array
        0부터 1까지 quantile을 균등하게 나눈 후에 이에 해당하는 값들을 reference_values에 저장함.
        '''
        self.reference_values=np.round(np.quantile(x,self.quantiles),decimals=self.decimals) # 이미 정렬된 값임
    def predict(self,x):
        '''
        주어진 값이 원래 분포에서 quantile값이 얼마였는지 유추하는 기능
        x : 1차원 벡터 numpy array
        '''
        # 대략적인 값의 구간 산출
        q=np.searchsorted(a=self.reference_values, v=x, side='right')
        right_wh=np.clip(q+1,0,self.n_subsample)
        left_wh=np.clip(q-1,0,self.n_subsample-1)
        left_score=self.reference_values[left_wh]
        right_score=self.reference_values[right_wh]
        coef=np.clip((x-left_score)/(right_score-left_score),0.0,1.0)
        # quantile값 조정
        mq=np.clip((q-1+coef)/self.n_subsample,0.0,1.0)
        return mq

 

3. 테스트

import numpy as np
qtf=quantiletransformer(n_subsample=500)

random_values=[
	np.random.randn(500)*0.01,
    np.random.randn(500)*0.05+1,
    np.random.randn(500)*10+2
    ]
random_values=np.concatenate(random_values,axis=None)

# fitting
qtf.fit(x=random_values)
# 1개 값 예측
print(qtf.predict(x=20))
# 여러 개 값 예측
print(qtf.predict(x=np.array([1,2,3,20,-8]))

# 저장된 reference값 확인
print(qtf.reference_values[:100])
# 상응하는 quantile값 확인
print(qtf.quantiles[:100])

# 저장하기
import dill
path='/path/to/save.dill'
with open(path,'wb') as f:
	dill.dump(qtf,f)
    f.close()

# 새로운 터미널 열고 다시 진행
import dill
import numpy as np #<-numpy array는 다시 로딩해줘야함.
path='/path/to/save.dill'
with open(path,'rb') as f:
	qtf2=dill.load(f)
    f.close()

# 1개 값 예측
print(qtf.predict(x=20))
# 여러 개 값 예측
print(qtf.predict(x=np.array([1,2,3,20,-8]))
# 저장된 reference값 확인
print(qtf.reference_values[:100])
# 상응하는 quantile값 확인
print(qtf.quantiles[:100])
728x90
반응형