강의영상

- (1/3) rand, randn

- (2/3) randint

- (3/3) choice, 통계분포, np.where/np.argwhere, 인덱싱고급, np.ix_

import

import numpy as np

numpy공부 5단계: 랜덤모듈

np.random.rand()

- 0~1사이에서 10개의 난수 생성

np.random.rand(10)
array([0.9762396 , 0.62290682, 0.65602078, 0.22890413, 0.01139937,
       0.71156552, 0.22585515, 0.98642156, 0.20169783, 0.52544263])

- 0~2사이에서 10개의 난수 생성

np.random.rand(10)*2 
array([0.19486166, 1.31320638, 1.75920753, 0.03976132, 0.65443053,
       0.98238346, 0.81586536, 1.26374209, 0.05189084, 1.53713552])

- 1~2사이에서 10개의 난수 생성

np.random.rand(10)+1
array([1.14697821, 1.52687013, 1.10827739, 1.87820387, 1.81630002,
       1.93842216, 1.30725718, 1.21386634, 1.9331912 , 1.29694134])

- 1~3사이에서 10개의 난수 생성

np.random.rand(10)*2+1 # 1~3
array([2.10122574, 2.67412063, 2.70573365, 1.49312813, 2.72674064,
       2.20040351, 2.26697979, 1.07834112, 2.6602285 , 1.60157633])

np.random.randn()

- N(0,1)에서 10개 추출

np.random.randn(10) # 표준정규분포에서 10개의 샘플 추출 
array([-0.40371384,  0.56295305, -1.03454983, -0.67628805, -0.89951532,
       -0.1925445 ,  1.43684725,  0.34022492,  0.96763699, -2.0699127 ])

- N(1,1)에서 10개 추출

np.random.randn(10)+1 
array([ 0.69440765, -0.58892798,  1.86823224,  1.50473088,  1.56127732,
        1.53295801, -0.44982257,  0.41660235,  0.50013233,  3.07135415])

- N(0,4)에서 10개 추출 (평균이 0이고 분산이 4인 분포)

np.random.randn(10)*2
array([ 0.48765347, -2.686622  ,  6.03529241,  0.52181081,  5.31070099,
       -1.02246697, -0.3058778 ,  0.16147941, -2.11923353, -2.55772141])

- N(3,4)에서 10개 추출

np.random.randn(10)*2+3 
array([6.20706555, 3.95308508, 7.02954382, 2.57838168, 3.40580485,
       4.37254926, 3.94572032, 2.32058837, 3.74756129, 4.81608642])

np.random.randint()

- [0,7)의 범위에서 하나의 정수를 랜덤으로 생성

np.random.randint(7) # [0,7)의 범위에서 하나의 정수 생성 
2

- [0,7)의 범위에서 20개의 정수를 랜덤으로 생성

np.random.randint(7,size=(20,)) # [0,7)의 범위에서 20개의 정수 생성 
array([5, 6, 6, 0, 6, 6, 2, 0, 3, 6, 2, 3, 2, 2, 6, 6, 5, 2, 3, 2])

- [0,7)의 범위에서 (2,2) shape 으로 정수를 랜덤으로 생성

np.random.randint(7,size=(2,2)) # [0,7)의 범위에서 (2,2) shape의 정수 생성 
array([[6, 4],
       [3, 1]])

- 위와 같은 코드를 아래와 같이 구현가능

np.random.randint(low=7,size=(5,5)) # [0,7)의 범위에서 (5,5) shape의 정수 생성 
array([[4, 1, 2, 0, 4],
       [5, 0, 1, 1, 3],
       [2, 1, 4, 6, 6],
       [4, 1, 6, 1, 5],
       [4, 2, 1, 3, 4]])

- [10,20) 의 범위에서 (5,5) shape 정수를 랜덤으로 생성

np.random.randint(low=10,high=20,size=(5,5)) # [10,20)의 범위에서 (5,5)shape의 정수생성 
array([[10, 13, 11, 15, 17],
       [10, 16, 15, 15, 11],
       [15, 14, 11, 19, 11],
       [10, 13, 13, 13, 14],
       [14, 19, 17, 13, 19]])

- 의문: np.random.randint(low=7,size=(5,5)) 가 좀 이상하다. 사실 np.random.randint(high=7,size=(5,5))가 되어야 맞지 않는가?

-> 저도 그렇게 생각하긴 하는데요, 구현이 이렇게 되어있습니다. 도움말 확인!

Return random integers from the "discrete uniform" distribution of the specified dtype in the "half-open" interval [`low`, `high`). If `high` is None (the default), then results are from [0, `low`).

np.random.choice()

- ver1

np.random.choice(5,20) # [0,5)에서 20개를 뽑음, 중복허용 
array([1, 1, 4, 3, 0, 2, 4, 4, 4, 4, 0, 4, 2, 2, 2, 2, 2, 1, 4, 1])
  • 이것은 np.random.randint(5,size=(20,)) 와 같은 코드임

- ver2

np.random.choice([0,1,2,3],20) # [0,1,2,3]에서 20개를 뽑음, 중복허용
array([1, 0, 0, 1, 3, 3, 0, 1, 0, 0, 3, 3, 0, 1, 2, 3, 2, 1, 2, 3])
np.random.choice(["apple","orange","banana"],20)
array(['orange', 'orange', 'orange', 'apple', 'orange', 'apple', 'apple',
       'apple', 'orange', 'orange', 'orange', 'apple', 'apple', 'banana',
       'banana', 'orange', 'orange', 'orange', 'orange', 'banana'],
      dtype='<U6')
np.random.choice(["apple","orange","banana"],2,replace=False) # 중복허용 X 
array(['banana', 'orange'], dtype='<U6')

통계분포

np.random.binomial(n=10,p=0.2,size=(5,)) # X1, ..., X5 ~ B(10,0.2) 
array([0, 1, 4, 1, 3])
np.random.normal(loc=10,scale=2,size=(5,)) # X1, ..., X5 ~ N(10,4) 
array([ 8.33296606,  7.28476525, 10.53464049,  8.70471009,  8.54969039])
  • np.radom.randn(5)*2 + 10와 같은코드
np.random.uniform(low=2,high=4,size=(5,)) # X1, ..., X5 ~ U(2,4) 
array([3.77048793, 2.5993732 , 2.93630494, 2.43154214, 3.63709163])
  • np.random.rand(5)*2+2와 같은 코드
np.random.poisson(lam=5,size=(5,)) # X1,...,X5 ~ Poi(5) 
array([4, 9, 4, 5, 0])

numpy공부 6단계: 기타 유용한 기본기능들

np.where, np.argwhere

- 1차원

a=np.array([0,0,0,1,0])
a
array([0, 0, 0, 1, 0])
np.where(a==1) # 조건 a==1을 만족하는 인덱스를 출력하라!
(array([3]),)
np.argwhere(a==1)
array([[3]])

- 2차원

np.random.seed(43052)
a=np.random.randn(12).reshape(3,4)
a
array([[ 0.38342049,  1.0841745 ,  1.14277825,  0.30789368],
       [ 0.23778744,  0.35595116, -1.66307542, -1.38277318],
       [-1.92684484, -1.4862163 ,  0.00692519, -0.03488725]])
np.where(a<0) # 조건을 만족하는 인덱스가 (1,2), (1,3), (2,0), (2,1), (2,3) 이라는 의미
(array([1, 1, 2, 2, 2]), array([2, 3, 0, 1, 3]))
np.argwhere(a<0) # 조건을 만족하는 인덱스가 (1,2), (1,3), (2,0), (2,1), (2,3) 이라는 의미
array([[1, 2],
       [1, 3],
       [2, 0],
       [2, 1],
       [2, 3]])
a[np.where(a<0)] # 조건을 만족하는 인덱스가 모두 출력 => 1차원 array로 출력 
array([-1.66307542, -1.38277318, -1.92684484, -1.4862163 , -0.03488725])
a[np.argwhere(a<0)] # 출력불가능
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Input In [133], in <cell line: 1>()
----> 1 a[np.argwhere(a<0)]

IndexError: index 3 is out of bounds for axis 0 with size 3
a[np.argwhere(a<0)[0][0],np.argwhere(a<0)[0][1]] # 어거지로 출력할수는 있음 
-1.6630754187023522

- np.where의 특수기능

np.random.seed(43052) 
a=np.random.randn(12).reshape(3,4) 
a
array([[ 0.38342049,  1.0841745 ,  1.14277825,  0.30789368],
       [ 0.23778744,  0.35595116, -1.66307542, -1.38277318],
       [-1.92684484, -1.4862163 ,  0.00692519, -0.03488725]])
np.where(a<0,0,a) # a<0을 체크 => 조건에 맞으면 0 => 조건에 안맞으면 a 
array([[0.38342049, 1.0841745 , 1.14277825, 0.30789368],
       [0.23778744, 0.35595116, 0.        , 0.        ],
       [0.        , 0.        , 0.00692519, 0.        ]])
np.where(a<0,0,1) # a<0을 체크 => 조건에 맞으면 0 => 조건에 안맞으면 1
array([[1, 1, 1, 1],
       [1, 1, 0, 0],
       [0, 0, 1, 0]])

- 요약

  • np.where: 인덱스의 좌표를 읽는 가독성은 떨어짐. 그런데 조건에 맞는 원소를 출력하거나 처리하는 (특수기능) 목적으로는 좋은 함수
  • np.argwhere: 인덱스의 좌표를 읽는 가독성은 좋은 편임. 그런데 조건에 맞는 원소를 출력하거나 처리하는 기능은 떨어짐

인덱싱고급

- 원래 a는 2d array

a=np.arange(12).reshape(3,4)
a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

- 경우1: 인덱싱 결과가 1d array로 나올수 있음

a[0,:] # 인덱싱의 결과 축의 갯수가 바뀐다! 2d array -> 1d array
array([0, 1, 2, 3])

- 경우2: 물론 인덱싱 결과가 2d array로 나올 수도 있음

a[[0,1],:] # 이것은 축의 숫자가 유지된다. 2d array -> 2d array 
array([[0, 1, 2, 3],
       [4, 5, 6, 7]])

- 경우1의 상황에서도 축의 갯수를 유지하면서 인덱싱하려면?

a[[0],:] # 이번에는 인덱싱의 결과 축의 갯수가 유지된다! 2d array -> 2d array
array([[0, 1, 2, 3]])
a[:,[0]] #
array([[0],
       [4],
       [8]])

- 미묘한 차이를 이해할것

a[0,:], a[[0],:]
(array([0, 1, 2, 3]), array([[0, 1, 2, 3]]))
a[:,0], a[:,[0]]
(array([0, 4, 8]),
 array([[0],
        [4],
        [8]]))

np.ix_

- 아래의 인덱싱을 비교하자.

a=np.arange(12).reshape(3,4)
a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
a[0:2,0:2]
array([[0, 1],
       [4, 5]])
a[[0,1],0:2]
array([[0, 1],
       [4, 5]])
a[0:2,[0,1]]
array([[0, 1],
       [4, 5]])

- 언뜻 생각하면 위의 결과와 a[[0,1],[0,1]]는 결과가 동일할 것 같다.

a[[0,1],[0,1]]
array([0, 5])
  • 실제로는 [a[0,0],a[1,1]]이 array로 나옴

- 사실 np.where에서 이미 관찰하였음

a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
np.where(a % 5 ==0)
(array([0, 1, 2]), array([0, 1, 2]))
a[np.where(a % 5 ==0)]
array([ 0,  5, 10])
a[[0, 1, 2],[0, 1, 2]]
array([ 0,  5, 10])

- a[[0,1],[0,1]]이 a[0:2,0:2]를 의미하게 하려면 아래와 같이 하면 된다.

a[np.ix_([0,1],[0,1])] # 유용해보이지만 생각보다 잘 쓰이는건 아님 
array([[0, 1],
       [4, 5]])

숙제

np.random.uniform(low=1.3,high=1.7,size=(10,))
array([1.42531485, 1.54567744, 1.44735207, 1.33217747, 1.48856969,
       1.47329978, 1.38976795, 1.30469965, 1.66634909, 1.65330027])

위와 같은코드를 np.random.rand()를 이용하여 구현하라.