[Python numpy] np.random.choice() 메소드로 임의표본 추출하기 (무작위, 확률 샘플링)
Python 분석과 프로그래밍/Python 데이터 전처리 2020. 8. 5. 19:44이번 포스팅에서는 Python numpy 모듈의 random.choice() 메소드를 사용하여 임의(무작위, 확률) 추출 (random sampling)하는 방법을 소개하겠습니다.
numpy.random.choice() 메소드의 기본 Syntax는 아래와 같습니다. 각 parameter별로 예를 들어서 설명을 해보겠습니다.
numpy.random.choice(a, size=None, replace=True, p=None)
이때 표본을 추출할 모집단에 해당하는 a 는 1-D array-like 또는 np.arange(n) 의 정수가 됩니다.
(1) 1부터 5까지의 정수 모집단에서 3개의 균등확률표본을 복원추출 하기 (Generate a uniform random sample from np.arange(5) of size 3) |
표본이 뽑힐 확률 p를 명시적으로 지정해주지 않으면 모든 원소가 뽑힐 확률이 동일한 (즉, p=1/N) 균등확률분포를 가정하고 표본이 추출됩니다.
그리고, 복원추출(replacement)이 기본 설정값이므로 똑같은 값이 2번 이상 표본으로 뽑힐 수도 있습니다.
import numpy as np Out[3]: array([4, 0, 0]) |
참고로, 위의 np.random.choice(5, 3) 코드는 np.random.randint(0,5,3) 과 동일합니다.
균등확률분포로 부터 임의 추출이므로 매번 표본으로 뽑히는 값이 바뀌게 됩니다. 위와 코드는 같지만 추출된 표본은 다르지요?
np.random.choice(5, 3) # sampled with different values Out[4]: array([2, 0, 0]) |
복원추출을 하게 되면 1~5 의 정수를 가지는 모집단에서 5개를 초과하는 표본을 뽑는데 문제가 없습니다.
np.random.choice(5, 10) # with replacement Out[5]: array([2, 2, 4, 2, 4, 0, 0, 4, 3, 2]) |
(2) 1~5의 정수 모집단에서 비균등 확률 p 로 3개 원소 임의 표본 복원추출 하기 (Generate a non-uniform random sample from np.arange(5) of size 3:) |
만약 모집단 내 각 원소별로 표본으로 뽑힐 확률 p를 알고 있다면, 혹은 명시적으로 지정을 해주고 싶다면 모수 p에 표본이 추출될 확률을 입력해주면 됩니다.
p = [0.1, 0, 0.3, 0.6, 0] np.random.choice(5, 3, p=p) Out[7]: array([2, 3, 3]) |
만약 표본을 추출할 모집단(a)의 원소 개수(n)과 각 원소별 표본이 뽑힐 확률(p)의 원소 개수가 서로 다를 경우 ValueError 가 발생합니다. (아래 예에서는 확률 p에는 3개가, 모집단 a는 5개 원소로서 서로 다름)
# ValueError: 'a' and 'p' must have same size p = [0.1, 0, 0.3] # size 3 np.random.choice(5, 3, p=p) # size 5 ValueError: 'a' and 'p' must have same size |
만약 모집단 원소별 표본으로 뽑힐 확률 p의 전체 합이 1 이 아니거나 0~1사이 값이 아닌 경우도 ValueError가 발생합니다. 왜냐하면, 확률의 정의 상 (1) 각 사건별 확률의 전체 합은 1이고, (2) 각 사건별 확률은 0~1 사이의 실수를 가져야 하기 때문입니다.
# ValueError: probabilities do not sum to 1 p = [0.4, 0, 0.3, 0.6, 0] # sum to 1.3 (not 1) np.random.choice(5, 3, p=p) ValueError: probabilities do not sum to 1 # ValueError: probabilities are not non-negative p = [-0.4, 0, 0.3, 1.6, 0] np.random.choice(5, 3, p=p) ValueError: probabilities are not non-negative |
(3) 1~5 정수 모집단에서 3개의 균등확률표본을 비복원추출(non-replacement) 하기 (Generate a uniform random sample from np.arange(5) of size 3 without replacement) |
옵션 중에서 replace=False 로 설정을 해주면 비복원추출(without replacement)을 합니다. 즉, 모집단에서 표본을 추출할 때 각 원소를 딱 한번만 추출하기 때문에 동일한 원소가 2번 이상 뽑히는 일은 없습니다. (default 옵션은 replace=True 임)
# Generate a uniform random sample from np.arange(5) of size 3 without replacement: np.random.choice(5, 3, replace=False) Out[11]: array([3, 2, 1]) |
참고로 위의 np.random.choice(5, 3, replace=False) 코드는 np.random.permutation(np.arange(5))[:3] 과 동일합니다.
비복원추출을 할 때는 한가지 조심해야 할 것이 있는데요, 모집단의 원소 개수보다 많은 수의 샘플을 비복원추출(replace=False)하려고 하면 ValueError가 발생합니다. (아래 예처럼, 5개의 원소를 가진 모집단에서 10개 표본을 비복원(즉, 중복 없이) 추출할 수는 없겠지요!)
# ValueError: Cannot take a larger sample than population when 'replace=False' np.random.choice(5, 10, replace=False) ValueError: Cannot take a larger sample than population when 'replace=False' |
위의 (2)번에서 표본추출확률 p 를 설정하는 것과, 이번 (3)번의 비복원추출(replace=False)을 함께 설정해줌으로써 비균등확률(non-uniform random sample)로 비복원추출(without replacement) 샘플링도 물론 가능합니다.
# Generate a non-uniform random sample from np.arange(5) of size 3 without replacement: p = [0.1, 0, 0.3, 0.6, 0] np.random.choice(5, 3, replace=False, p=p) Out[13]: array([3, 0, 2]) |
(4) 정수 대신에 임의의 배열처럼 생긴 객체의 원소를 확률추출하기 (Any of the above can be repeated with an arbitrary array-like instead of just integers.) |
np.random.choice(a, size=None, replace=True, p=None) 의 syntax에서 a 부분에 정수 배열 (np.arange(n)) 말고도 1-D array-like 객체를 대상으로 할 수도 있습니다. 아래 예에서는 과일 이름을 원소로 가지는 리스트로부터 비복원 비균등 확률 표본추출을 해보았습니다.
# Any of the above can be repeated with an arbitrary array-like instead of just integers. fruits = ['apple', 'banana', 'cherries', 'durian', 'grapes', 'lemon', 'mango'] p = [0.1, 0, 0.2, 0.5, 0.1, 0.05, 0.05] np.random.choice(fruits, 3, p=p, replace=False) Out[14]: array(['cherries', 'lemon', 'durian'], dtype='<U8') |
(5) 초기값 설정을 통한 재현가능성 확보 (setting seed number for reproducibility) |
np.random.seed() 로 초기값(seed value)을 설정해주면 매번 똑같은 확률표본을 추출할 수 있습니다. 만약 재현가능성(reproducibility)이 필요한 경우라면 초기값을 설정해주세요.
# set seed number for reproducibility np.random.seed(1004) np.random.choice(5, 3) Out[15]: array([2, 3, 3]) np.random.seed(1004) np.random.choice(5, 3) Out[16]: array([2, 3, 3]) |
참고로, 기계학습을 할 때 train set, test set 을 무작위로 분할하는 여러가지 방법은 https://rfriend.tistory.com/519 를 참고하시기 바랍니다.
많은 도움이 되었기를 바랍니다.
이번 포스팅이 도움이 되었다면 아래의 '공감~
'를 꾹 눌러주세요. :-)
* Reference: https://docs.scipy.org/doc//numpy-1.10.4/reference/generated/numpy.random.choice.html