[NumPy] NumPy 기본 문법

Hyeonsol Kong·2022년 4월 10일
0

Machine Learning

목록 보기
2/2

시작하는 글

기계학습의 빠른 연산을 위해서 파이썬의 리스트보다는, NumPy의 배열을 자주 사용한다.
본격적으로 기계학습에 대해서 배워보기 전, NumPy에 익숙해져보자 :>

프로그래밍을 공부하는 학생이 지식 정리 및 공유를 위해 작성한 글으로, 정확하지 않은 내용이 있을 수 있습니다. 지적과 지식 공유는 환영합니다!

NumPy 배열

  • Python의 리스트를 NumPy의 배열로 변환할 수 있다.
    np_arr = np.array(arr)
  • 각 원소에 대한 연산을 빠르게 진행할 수 있다.
# Python 리스트
# 각각의 원소마다 연산을 진행해줘야 함
for i in range(len(arr_x)):
	gradient.append(arr_y[i] / arr_x[i])
[1, 2, 3] + [4, 5, 6] == [1, 2, 3, 4, 5, 6]
    
    
# NumPy 배열
# 같은 인덱스를 가진 원소끼리의 연산을 진행해줌
gradient = np_arr_y / np_arr_x
[1, 2, 3] + [4, 5, 6] == [5, 7, 9]
  • 마찬가지로, 원소를 추려낼 때 조건만 적어주면 된다.
# 원소의 값이 10 이상인 값만 추릴 때
np_arr[np_arr >= 10]

다차원 배열

np_arr = np.array([1, 2, 3, 4])
np_arr.shape # (4,) 1차원, 길이 4
np_arr.size	# 4, 전체 원소의 개수

np_arr.reshape(4, 1)
'''
[[1]
 [2]
 [3]
 [4]]			2차원 (4 * 1)
'''
np_arr.reshape(2, 2)
'''
[[1, 2]
 [3, 4]]		2차원 (2 * 2)
'''
np_arr.reshape(1, 4)
'''
[[1, 2, 3, 4]]	2차원 (1 * 4)
'''

np_d_arr = np.array([[1, 2], [3, 4]])
np_f_arr = np_d_arr.flatten()
np_f_arr == np_arr # TRUE

위의 1차원 배열을 reshape() 함수를 통해서 다차원 배열로 만들 수 있다. 마찬가지로, 다차원 배열을 flatten()을 통해 1차원 배열로 만들 수 있다. 값은 동일하지만, 이를 어떻게 해석할 지를 결정하는 것이다.
(컴퓨터에 저장될 때에는 어차피 1차원으로 메모리에 저장되기 때문에 이를 어떻게 해석할 지는 우리의 몫이다.)

배열 초기화

empty_arr = np.empty((2, 2))	# 초기화되지 않은 값. 예상치 못한 값이 들어있음
zeros_arr = np.zeros((2, 3))	# 0으로 초기화된 값.
ones_arr = np.ones((4, 2))
tens_arr = np.full((2, 2), 10)
zeros_like_arr = np.zeros_like(ones_arr) # ones_arr와 같은 모양, 0으로 초기화
ones_like_arr = np.ones_like(zeros_arr) # zeros_arr와 같은 모양, 1로 초기화
full_like_arr = np.full_like(zeros_arr, 0.1)

범위 내에서 배열 만들기

range_arr = np.arange(0, 10, 1)	# [0, 10) 범위, 스텝 1
linspace_arr = np.linspace(2, 3, 5)	#[2, 3] 범위에서 5개

위 두 함수의 차이점
np.arange - 간격을 정해준다, np.linspace - 개수를 정해준다

np.arange에서 일어날 수 있는 문제; 정확성 문제가 일어날 수 있음!

Another stability issue is due to the internal implementation of numpy.arange. The actual step value used to populate the array is dtype(start + step) - dtype(start) and not step. Precision loss can occur here, due to casting or due to using floating points when start is much larger than step. This can lead to unexpected behaviour.

> np.arange(0, 5, 0.5, dtype=int)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
> np.arange(-3, 3, 0.5, dtype=int)
array([-3, -2, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8])

In such cases, the use of numpy.linspace should be preferred.
출처 : https://numpy.org/doc/stable/reference/generated/numpy.arange.html


Random 값으로 채운 배열

uniform_rand_arr = np.random.rand(3, 2)		# [0, 1) 범위 실수, size=(3,2)
range_rand_int_arr = np.random.randint(5, size=(2, 4))	# [0, 5) 범위 정수
np.random.randn(size) # size 크기로 표준정규분포(평균 0, 표준편차 1)에서 random으로 추출
# 정규분표를 따르는 데이터를 만드는 데 적합하다.

위에서 np.random.randn 의 경우 단순히 함수명만 보았을 때 이해하기 힘들었는데 어떤 함수냐 하면, 정규분포를 따르는 데이터를 생성할 때

평균 + 표준편차 * np.random.randn( )

위 식을 통해서 간편하게 사용할 수 있도록, 표준정규분포에서 random으로 값을 추출하는 것이다.
표준정규분포는 평균이 0이고, 표준편차가 1이기 때문에, np.random.randn()에서 0이 나올 확률이 제일 많고, 0에서 먼 값일 수록 나올 확률이 적어진다. 그 값에 표준편차를 곱하고, 평균을 더하면 내가 원하는 평균과 표준편차를 가지는 정규분포 상의 데이터를 만들 수 있다!

조금 더 깊게, 이 함수가 만들어진 이유에 대해서 생각해보자.

중심 극한 정리
표본의 크기가 커질수록 표본 평균의 분포는 모집단의 분포 모양과는 관계없이 정규분포에 가까워진다.

위 정리에 의하여, 정규분포와는 전혀 다른 집단에서 무작위로 충분히 많은 수를 추출하면, 표본평균의 분포가 정규분포에 가깝게 되기 때문에 이 함수를 자주 사용할 수 있는 것이다.

슬라이싱

3차원 배열에서 첫 번째 묶음 가져오기 : np_arr[0, :, :] == np_arr[0]
3차원 배열에서 짝수 번째 묶음 가져오기 : np_arr[0::2], 앞의 문자열 슬라이싱과 같음

깊은 복사 / 얕은 복사

깊은 복사 : np_copy = np.copy(np_arr)
얕은 복사( 같은 id를 가짐) : np_copy = np_arr

여러 항목의 값 한꺼번에 수정

3차원 배열에서, 2번째 묶음 3번째 행의 값을 모두 1로 바꾸기 : np_arr[1, 2] = 1

배열 이어붙이기

array1 = np.array([[1, 2], [3, 4]])	# shape (2, 2)
array2 = np.array([[5, 6]])	# shape (1, 2)

두 배열을 붙일 때에는, 기준이 되는 축 이외의 값이 같아야 한다.
즉, 위 예제에서는 열의 모양이 같기 때문에, 행을 추가하는 식으로 붙여야 한다.

concatenated_array1 = np.concatenate((array1, array2), axis=0)
# (2, 2) (1, 2)을 0번째 인덱스로 더한다. -> (3, 2)
'''
[[1, 2]
 [3, 4]
 [5, 6]]
'''
concatenated_array2 = np.concatenate((array1, array2), axis=1) # error!
'''
[[1, 2] [5, 6]
 [3, 4] ??????] <-ERROR
'''

0개의 댓글