다운로드
작성자: admin 작성일시: 2016-09-23 11:05:37 조회수: 15990 다운로드: 276
카테고리: Python 태그목록:

난수 발생과 카운팅

파이썬을 이용하여 데이터를 무작위로 섞거나 임의의 수 즉, 난수(random number)를 발생시키는 방법에 대해 알아본다. 이 기능은 주로 NumPy의 random 서브패키지에서 제공한다.

시드 설정하기

컴퓨터 프로그램에서 발생하는 무작위 수는 사실 엄격한 의미의 무작위 수가 아니다. 어떤 특정한 시작 숫자를 정해 주면 컴퓨터가 정해진 알고리즘에 의해 마치 난수처럼 보이는 수열을 생성한다. 이런 시작 숫자를 시드(seed)라고 한다. 일단 생성된 난수는 다음번 난수 생성을 위한 시드값이 된다. 따라서 시드값은 한 번만 정해주면 된다. 시드는 보통 현재 시각등을 이용하여 자동으로 정해지지만 사람이 수동으로 설정할 수도 있다. 특정한 시드값이 사용되면 그 다음에 만들어지는 난수들은 모두 예측할 수 있다. 이 책에서는 코드의 결과를 재현하기 위해 항상 시드를 설정한다.

파이썬에서 시드를 설정하는 명령은 seed이다. 인수로는 0과 같거나 큰 정수를 넣어준다.

In:
np.random.seed(0)

이렇게 시드를 설정한 후 rand 명령으로 5개의 난수를 생성해 보자. 다른 난수 관련 명령어를 실행하지 말고 바로 다음 명령을 실행해야 한다. rand 명령은 0과 1사이의 난수를 발생시키는 명령으로 인수로 받은 숫자 횟수만큼 난수를 발생시킨다.

In:
np.random.rand(5)
Out:
array([ 0.5488135 ,  0.71518937,  0.60276338,  0.54488318,  0.4236548 ])

몇번 더 난수를 생성해보자. 사람이 예측할 수 없는 무작위 숫자가 나오는 것을 볼 수 있다.

In:
np.random.rand(10)
Out:
array([ 0.64589411,  0.43758721,  0.891773  ,  0.96366276,  0.38344152,
        0.79172504,  0.52889492,  0.56804456,  0.92559664,  0.07103606])
In:
np.random.rand(10)
Out:
array([ 0.0871293 ,  0.0202184 ,  0.83261985,  0.77815675,  0.87001215,
        0.97861834,  0.79915856,  0.46147936,  0.78052918,  0.11827443])

이제 시드를 0으로 재설정하고 다시 난수를 발생시켜 본다.

In:
np.random.seed(0)
In:
np.random.rand(5)
Out:
array([ 0.5488135 ,  0.71518937,  0.60276338,  0.54488318,  0.4236548 ])
In:
np.random.rand(10)
Out:
array([ 0.64589411,  0.43758721,  0.891773  ,  0.96366276,  0.38344152,
        0.79172504,  0.52889492,  0.56804456,  0.92559664,  0.07103606])
In:
np.random.rand(10)
Out:
array([ 0.0871293 ,  0.0202184 ,  0.83261985,  0.77815675,  0.87001215,
        0.97861834,  0.79915856,  0.46147936,  0.78052918,  0.11827443])

아까와 같은 숫자가 나오는 것을 확인할 수 있다.

데이터의 순서 바꾸기

데이터의 순서를 바꾸려면 shuffle 명령을 사용한다.

In:
x = np.arange(10)
x
Out:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In:
np.random.shuffle(x)
x
Out:
array([3, 6, 4, 5, 2, 9, 7, 8, 1, 0])

데이터 샘플링

이미 있는 데이터 집합에서 일부를 무작위로 선택하는 것을 샘플링(sampling)이라고 한다. 샘플링에는 choice 명령을 사용한다. choice 명령은 다음과 같은 인수를 가질 수 있다.

numpy.random.choice(a, size=None, replace=True, p=None)

  • a : 배열이면 원래의 데이터, 정수이면 range(a) 명령으로 데이터 생성
  • size : 정수. 샘플 숫자
  • replace : 불리언. True이면 한번 선택한 데이터를 다시 선택 가능
  • p : 배열. 각 데이터가 선택될 수 있는 확률
In:
np.random.choice(5, 5, replace=False)  # shuffle 명령과 같다.
Out:
array([1, 4, 0, 3, 2])
In:
np.random.choice(5, 3, replace=False)  # 3개만 선택
Out:
array([2, 1, 3])
In:
np.random.choice(5, 10) # 반복해서 10개 선택
Out:
array([0, 4, 1, 4, 1, 2, 2, 0, 1, 1])
In:
np.random.choice(5, 10, p=[0.1, 0, 0.3, 0.6, 0])  # 선택 확률을 다르게 해서 10개 선택
Out:
array([0, 3, 3, 2, 2, 3, 3, 2, 0, 3])

난수 생성

NumPy의 random 서브패키지에는 난수를 생성하는 다양한 명령을 제공한다. 그 중 가장 간단하고 많이 사용되는 것은 다음 3가지 명령이다.

  • rand: 0부터 1사이의 균일 분포
  • randn: 가우시안 표준 정규 분포
  • randint: 균일 분포의 정수 난수

rand 명령은 0부터 1사이에서 균일한 확률 분포로 실수 난수를 생성한다. 숫자 인수는 생성할 난수의 크기이다. 여러개의 인수를 넣으면 해당 크기를 가진 행렬을 생성한다.

In:
np.random.rand(10)
Out:
array([ 0.95894927,  0.65279032,  0.63505887,  0.99529957,  0.58185033,
        0.41436859,  0.4746975 ,  0.6235101 ,  0.33800761,  0.67475232])
In:
np.random.rand(3, 5)
Out:
array([[ 0.31720174,  0.77834548,  0.94957105,  0.66252687,  0.01357164],
       [ 0.6228461 ,  0.67365963,  0.971945  ,  0.87819347,  0.50962438],
       [ 0.05571469,  0.45115921,  0.01998767,  0.44171092,  0.97958673]])

randn 명령은 기댓값이 0이고 표준편차가 1인 가우시안 표준 정규 분포를 따르는 난수를 생성한다. 인수 사용법은 rand 명령과 같다.

In:
np.random.randn(10)
Out:
array([-0.30237513, -2.2244036 ,  0.72400636,  0.35900276,  1.07612104,
        0.19214083,  0.85292596,  0.01835718,  0.42830357,  0.99627783])
In:
np.random.randn(3, 5)
Out:
array([[-0.49114966,  0.71267817,  1.11334035, -2.15367459, -0.41611148],
       [-1.07089699,  0.22113881, -1.12305712, -1.05075796,  1.01207905],
       [ 1.54371643, -0.40211489,  0.8647491 , -0.22686923,  0.81116027]])

randint 명령은 다음과 같은 인수를 가진다.

numpy.random.randint(low, high=None, size=None)

만약 high를 입력하지 않으면 0과 low사이의 숫자를, high를 입력하면 lowhigh는 사이의 숫자를 출력한다. size는 난수의 숫자이다.

In:
np.random.randint(10, size=10)
Out:
array([0, 4, 3, 6, 9, 8, 0, 8, 5, 9])
In:
np.random.randint(10, 20, size=10)
Out:
array([10, 19, 16, 15, 13, 11, 18, 10, 14, 19])
In:
np.random.randint(10, 20, size=(3,5))
Out:
array([[16, 15, 17, 18, 18],
       [19, 12, 18, 16, 16],
       [19, 11, 16, 18, 18]])

정수 데이터 카운팅

이렇게 발생시킨 난수가 실수값이면 히스토그램 등을 사용하여 분석하면 된다. 히스토그램을 시각화 부분에서 나중에 자세히 설명한다.

만약 난수가 정수값이면 unique 명령이나 bincount 명령으로 데이터 값을 분석할 수 있다. 이 명렬들은 random 서브패키지가 아니라 NumPy 바로 아래에 포함된 명령이다.

unique 명령은 데이터에서 중복된 값을 제거하고 중복되지 않는 값의 리스트를 출력한다. return_counts 인수를 True 로 설정하면 각 값을 가진 데이터 갯수도 출력한다.

In:
np.unique([11, 11, 2, 2, 34, 34])
Out:
array([ 2, 11, 34])
In:
a = np.array(['a', 'b', 'b', 'c', 'a'])
index, count = np.unique(a, return_counts=True)
In:
index
Out:
array(['a', 'b', 'c'],
      dtype='
In:
count
Out:
array([2, 2, 1])

그러나 unique 명령은 데이터에 존재하는 값에 대해서만 갯수를 세므로 데이터 값이 나올 수 있음에도 불구하고 데이터가 하나도 없는 경우에는 정보를 주지 않는다. 예를 들어 주사위를 10번 던졌는데 6이 한 번도 나오지 않으면 이 값을 0으로 세어주지 않는다.

따라서 데이터가 주사위를 던졌을 때 나오는 수처럼 특정 범위안의 수인 경우에는 bincountminlength 인수를 설정하여 쓰는 것이 더 편리하다. 이 때는 0 부터 minlength - 1 까지의 숫자에 대해 각각 카운트를 한다. 데이터가 없을 경우에는 카운트 값이 0이 된다.

In:
np.bincount([1, 1, 2, 2, 2, 3], minlength=6)
Out:
array([0, 2, 3, 1, 0, 0])

질문/덧글

np.random.seed 질문입니다. ecom*** 2017년 11월 12일 8:52 오전

우선 파이선 좋은 라이브러리 설명자료 감사드립니다.

한가지 궁금한 것은
np.random.seed() 설명에서 seed에 '0'을 넣었는데, 여기에 들어가는 정수가 어떤 의미를 가지는지 궁금합니다.
0과 100으로 넣어서 비슷해 보이던데요.

np.random.seed(100)
np.random.randint(1, 90, size =20)
(결과) array([ 9, 25, 68, 88, 80, 49, 11, 53, 54, 67, 15, 35, 25, 16, 61, 59, 17, 10, 87, 3])

np.random.seed(0)
np.random.randint(1, 90, size =20)
(결과) array([45, 48, 65, 68, 68, 10, 84, 22, 37, 88, 71, 89, 89, 13, 59, 66, 40, 88, 47, 89])

답변: np.random.seed 질문입니다. engk*** 2017년 12월 27일 11:50 오후

난수는 사실 진정한 의미의 난수가 아닙니다.
일정한 룰에 따라서 난수가 생성되죠.
따라서 실제 난수를 생성하면 컴퓨터의 시간등을 바탕으로 seed를 만들어 난수열을 생성합니다.

seed가 다르면 다른 값을 나타내게 됩니다.

np.random.choice 질문입니다. swso*** 2018년 1월 30일 3:33 오후

저에게 무척 유익한 설명 감사드립니다.
이 글을 보다보니 np.random.choice() 를 이용하여 데이터를 추출하는 과정에서 추가적으로 질문이 있습니다.
만약 100000개의 랜덤 데이터 'A' 에서 200개를 추출하고 싶고, 이때 이들의 확률을 같이 알고 싶다면
np.random.choice(A, 200, p=[0.01, 00.1, .... 0.3, 0.6, 0])
이런식으로 200개의 확률을 모두 지정해주는 방법 밖에는 없는것인가요??

답변: np.random.choice 질문입니다. 관리자 2018년 1월 30일 8:52 오후

확률을 아는 것이 아니라 지정해 주는 것입니다. 그리고 지정하는 방법은 위에서 설명한 방법뿐입니다.

답변: 답변: np.random.choice 질문입니다. swso*** 2018년 2월 6일 12:40 오후

답변 감사드립니다. 확률을 아는 것이 아니라 지정하는 방법이군요 .
그렇다면 혹시 데이터에서 확률을 추출하는 방법은 따로 없는지 궁굼합니다!