[NumPy_5] 난수 / 고유 항목 다루기 / 행렬 전치 / 배열 뒤집기 재구성
난수 생성
기계 학습 알고리즘을 구성하고 평가할 때 난수 생성은 중요한 역할을 한다.
인공 신경망의 가중치를 무작위로 초기화한다거나, 데이터를 무작위 세트로 분할하거나, 데이터 세트를 무작위로
셔플 하는 등 난수를 생성하는 일은 필수적이라고 할 만큼 많이 사용된다.
np.random.randint( )
기본 형태
np.random.randint(low, high, size=None)
low : [선택 사항] int 분포에서 가져올 가장 작은 정수 값 지정 , 생략 시 0부터 high 미만의 정수 반환
high : int 분포에서 가져올 가장 큰 정수 입력
size : [선택 사항] int or int (tuple) 입력, 출력 개수 혹은 shape 결정 기본 값은 None으로 단일 값이 반환
print(np.random.randint(2, size=10))
[1 0 1 0 1 1 1 1 1 0]
print(np.random.randint(5, size=(2,4)))
[[3 3 2 2]
[2 3 1 1]]
low , high 선택 시 ~이상 ~ 미만이 적용되어 low이상 high 미만 값이 적용된다.
np.random.rand( )
기본 형태
np.random.rand(d0, d1,... dn)
d0, d1, dn : [선택 사항] 반환할 배열의 shape를 int로 입력, 미기재 시 단일 값으로 반환 (size와 동일)
print(np.random.rand(3, 2))
[[0.76471719 0.05417888]
[0.09713495 0.93847261]
[0.43437567 0.26996139]]
입력한 값에 따라 shape를 반환하는데, 이때 반환 값은 0 이상 1 미만의 값으로 이루어진다.
np.random.randn( )
기본 형태
np.random.randn(d0, d1,,, dn)
d0, d1, dn : [선택 사항] 반환할 배열의 shape를 int로 입력, 미기재 시 단일 값으로 반환 (size와 동일)
print(np.random.randn(2,4))
[[ 0.27379276 0.23201572 -0.83806599 -1.55740584]
[-3.01155814 -2.45372117 -0.39718678 0.21331688]]
np.random.randn( )는 표준 정규 분포를 따르는 샘플 값을 반환한다.
np.random.shuffle( )
기본 형태
np.random.shuffle(x)
x : 섞일 배열 혹은 리스트를 의미
arr = np.arange(10)
np.random.shuffle(arr)
print(arr)
[4 3 5 8 0 7 6 1 9 2]
np.random.shuffle( )은 배열을 무작위로 섞어 제자리에서 시퀀스를 수정한다.
이 메서드는 다차원 배열의 첫 번째 축을 따른 배열만 섞기 때문에 하위 배열 간의 순서는 변경되지만
그 안의 내용은 동일하게 유지된다.
arr = np.arange(9).reshape((3,3))
np.random.shuffle(arr)
print(arr)
[[0 1 2]
[6 7 8]
[3 4 5]]
# 하위 배열 행의 순서는 섞였지만 열은 그대로 유지
np.random.choice( )
기본 형태
np.random.choice(a, size=None, replace = True, p = None)
a : int 또는 1차원 배열. int이면 임의 샘플이 a = np.arrange(a)인 것처럼 생성된다.
size : [선택 사항] int 또는 int (tuple)
- int가 입력되면 반환 값의 size, tuple이 입력되면 shape로 간주해(m, n, k) 일 때 m*n*k개의 샘플이 반환된다 기본값은 None으로 이 경우 단일 값이 반환됨
replace : [선택 사항] boll. 샘플의 중복 여부
p : [선택 사항] 1차원 배열 a의 각 항목과 관련된 확률, 지정되지 않은 경우 샘플은 a의 모든 항목에 대해 균일한 분포
# np.arange(5)에서 3개의 샘플을 각각의 확률에 맞춰 생성
print(np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0]))
[0 2 2]
zoo = ['rabbit','lion','elephant','monkey']
print(np.random.choice(zoo, 5, p = [0.5, 0.1, 0.1, 0.3]))
['elephant' 'monkey' 'rabbit' 'elephant' 'monkey']
고유 항목 및 개수 얻기
np.unique( )
기본 형태
np.unique( arr,return_index = False, return_inverse = False, return_count = False, axis = None )
유니크 함수는 배열의 정렬된 고유 값을 오름차순으로 나열하여 반환하는 함수이다.
고유 값을 반환 하기 때문에 중복되는 요소를 없애고 하나씩만 남은 배열로 만들어준다.
고유 값 외에도 세가지 선택적 출력을 포함하고 있다.
- arr: 입력 배열 axis가 지정되지 않으면 1차원으로 반환한다.
- return_index : [선택 사항] True 인 경우 각 고유 값이 처음 나타나는 arr의 인덱스도 같이 반환한다.
- return_inverse : [선택 사항] True 인 경우 arr로 재구성할 때 사용할 수 있도록 arr을 반환 배열 인덱스로 나태 내 같이 반환한다.
- return_count : [선택 사항] True인 경우 각 고유 값이 arr에 나타나는 횟수도 함께 반환한다.
- axis : [선택 사항] 작업할 축을 int 형태로 입력한다, None이면 1차원 배열로 반환
import numpy as np
a = np.array([11,11,12,13,14,15,16,17,13,16,15])
unique_a = np.unique(a)
print(unique_a)
[11 12 13 14 15 16 17]
선택 사항을 제외하여 실행한 결과로 중복되는 요소 값을 제외하여 출력됐다.
import numpy as np
a = np.array([11,11,12,13,14,15,16,17,13,16,15])
unique_a = np.unique(a,True,True,True)
print(unique_a)
(array([11, 12, 13, 14, 15, 16, 17]), array([0, 2, 3, 4, 5, 6, 7]), array([0, 0, 1, 2, 3, 4, 5, 6, 2, 5, 4]), array([2, 1, 2, 1, 2, 2, 1]))
위에 언급한 선택 사항을 모두 입력하면 예시와 같이 그 값을 포함하여 새로운 배열로 반환을 하는데,
True로 표현을 하게 되면 순차적으로 실행이 되기 때문에 그중 원하는 값만을 추가하고자 한다면
return_index = True와 같이 작성해 사용하면 된다.
2차원 배열에서도 마찬가지로 사용이 가능하지만 axis가 입력되지 않으면 1차원 배열로 반환을 한다.
또, 2차원 배열은 행, 열의 구분이 있기 때문에 고유 행을 구하기 위해서는 axis = 0
고유 열을 구하기 위해서는 axis = 1로 지정하여 반환받아 사용한다.
arr2 = np.array([[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[1,2,3,4]])
arr2 = np.unique(arr2,axis=0)
print(arr2)
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
행렬의 전치, 재구성
기본 형태
numpy.transpose(a, axes =None)
- a : 입력 배열
- axes : [선택 사항] 튜플 또는 정수 리스트로 axes를 지정할 경우 [0,1,... , N-1]의 순열을 포함하는 튜플 또는 리스트여야 한다. N = a의 축 개 수, 지정하지 않은 경우 기본 값은 range(a.ndim)[::-1]이며 축 순서를 반대로 반환한다.
행렬의 전치란 특정 행렬의 행과 열을 맞바꾸는 것을 의미한다.
arr = np.arange(4).reshape((2,2))
print(arr)
[[0 1]
[2 3]]
print(np.transpose(arr))
[[0 2]
[1 3]]
간단한 형태로 코드를 실행하면 행과 열의 위치가 변환된 것을 쉽게 알 수 있다.
arr = np.ones((1,2,3))
print(arr)
print()
print(np.transpose(arr,(1,0,2)).shape)
[[[1. 1. 1.]
[1. 1. 1.]]]
(2, 1, 3)
#axes를 입력한 경우 반환 값
이제 프로그래밍에 어느 정도 익숙해진 분들이라면 알다시피, 개발자들은 타이핑을 길게 치는 걸 좋아하지 않는다.
다른 함수들에 비해 비교적 길이가 긴 transpose() 메서드는 T로 대체할 수 있다.
arr = np.array(([1.,2.],[3.,4.]))
print(arr)
[[1. 2.]
[3. 4.]]
print(arr.T)
[[1. 3.]
[2. 4.]]
배열 뒤집기
transpose() 메서드가 행렬의 위치를 바꾸는 함수였다면
np.flip( )은 배열의 내용을 축을 기준으로 뒤집어주는 함수이다. 축을 기준으로 하는 함수이지만,
축을 지정하지 않는다면 배열 전체를 뒤집어 반환한다.
#1차원 배열 뒤집기
arr = np.array([1,2,3,4,5,6,7,8])
print(np.flip(arr))
#2차원 배열 뒤집기
arr1 = np.array([[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[1,2,3,4]])
print(np.flip(arr1))
[[ 4 3 2 1]
[12 11 10 9]
[ 8 7 6 5]
[ 4 3 2 1]]
2차원 배열은 축을 지정하여 행, 열을 기준으로 뒤집을 수 있다.
# 행 기준으로 뒤집기
arr1 = np.array([[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[1,2,3,4]])
print(np.flip(arr1,axis=0))
[[ 1 2 3 4]
[ 9 10 11 12]
[ 5 6 7 8]
[ 1 2 3 4]]
# 열 기준으로 뒤집기
arr1 = np.array([[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[1,2,3,4]])
print(np.flip(arr1,axis=1))
[[ 4 3 2 1]
[ 8 7 6 5]
[12 11 10 9]
[ 4 3 2 1]]
1차원 배열로 구성하기
flatten( )
기본 형태
nmp.faltten(order='C')
- order : [선택 사항] C, F, A, K 중 선택, 기본 값은 C로 행을 우선, F는 열을 우선으로 평면화 한다.
arr = np.array([[1,2],[3,4]])
print(arr)
print(arr.flatten(order='F'))
[[1 2]
[3 4]]
[1 3 2 4]
ravel( )
기본 형태
np.ravel(a, order='C')
- a : 입력 배열
- order : [선택 사항] C, F, A, K 중 선택, 기본 값은 C로 행을 우선, F는 열을 우선으로 평면화 한다. 1
arr = np.array([[1,2,3],[4,5,6]])
print(arr)
print(np.ravel(arr,order='F'))
[[1 2 3]
[4 5 6]]
[1 4 2 5 3 6]
두 가지 함수 모두 동일한 기능을 가지고 있지만 프로그래밍 언어에서는 이유 없이 같은 기능을 넣는 경우가 거의 없다.
ravel()의 경우 부모 배열을 참조(=view) 하기 때문에 새로 만들어진 배열의 변경 사항이 상위 배열에도 영향을 준다.
그렇기 때문에 ravel은 메모리 효율 부분에서 우수하고, flatten()은 copy 방식이기 때문에 원본이 유지가 된다.
따라서 뭐가 더 좋다기보다는 각 상황과, 환경에 맞춰 사용하는 게 바람직하다.