1 Numpy 다루기
- 배열(array)는 벡터(1D) 또는 행렬(2D이상)
- List와 유사하나 List는 이종의 자료형이 가능하고, 수치 연산의 형태가 상이함
- 원소의 개수를 바꿀 수 없음
- Numpy는 배열 연산과 관련된 편리한 기능을 제공
- 적은 메모리 사용으로 연산속도가 빠름
- 벡터화 연산, 배열 인덱싱들을 통한 질의가 가능함
- 파이썬에서는 기본적으로 배열 자료형을 제공하지 않기 때문에 배열을 다루기 위해서는 numpy를 이용함
1.1 배열(Array) 만들기
값을 이용하여 배열 만들기
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a)
print(a.shape)
print(a.dtype)
결과
[[1 2 3]
[4 5 6]]
(2, 3)
int32
a = np.array([[1.0, 2, 3], [4, 5, 6]])
print(a)
print(a.shape)
print(a.dtype)
결과
[[1. 2. 3.]
[4. 5. 6.]]
(2, 3)
float64
a = a.astype(np.int32)
print(a)
print(a.dtype)
결과
[[1 2 3]
[4 5 6]]
int32
a = np.array([[1.2, 2.5, 3.7], [4, 5, 6]], dtype=np.int32)
print(a)
print(a.shape)
print(a.dtype)
결과
[[1 2 3]
[4 5 6]]
(2, 3)
int32
print(a.shape)
print(a.size)
print(len(a))
결과
(2, 3)
6
2
등간격의 배열 만들기
- arrange(처음값, 마지막 값, 간격) : 처음값부터 (마지막 값-1)까지 간격(default=1)으로 정수 생성
np.arange(0,10,2)
결과
array([0, 2, 4, 6, 8])
np.arange(0,10)
결과
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.arange(0,10.8,0.7)
결과
array([ 0. , 0.7, 1.4, 2.1, 2.8, 3.5, 4.2, 4.9, 5.6, 6.3, 7. ,
7.7, 8.4, 9.1, 9.8, 10.5])
np.arange(10,0,-1)
결과
array([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
np.arange(10)
결과
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
- linspace(시작값, 마지막값, 갯수) : 시작값(포함)부터 마지막값(포함)까지 등간격으로 갯수(default=50)만큼 값 생성
np.linspace(0,10,10)
결과
array([ 0. , 1.11111111, 2.22222222, 3.33333333, 4.44444444,
5.55555556, 6.66666667, 7.77777778, 8.88888889, 10. ])
np.linspace(5,-5,9)
결과
array([ 5. , 3.75, 2.5 , 1.25, 0. , -1.25, -2.5 , -3.75, -5. ])
empty, zeros, ones 배열 만들기
- empty(빈배열) : 현재 메모리에 있는 값 그대로 빈 공간만 생성
e = np.empty([3,3])
print(e)
결과
[[ 5. 3.75 2.5 ]
[ 1.25 0. -1.25]
[-2.5 -3.75 -5. ]]
- zeros(영배열) : 모든 원소가 0인 배열 생성
z = np.zeros([3,3], dtype=np.int32)
print(z)
결과
[[0 0 0]
[0 0 0]
[0 0 0]]
- ones(1배열) : 모든 원소가 1인 배열 생성
o = np.ones([3,3])
print(o)
결과
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
랜덤 배열 만들기
- seed는 랜덤값을 생성할 때, 시작점을 의미
- seed를 지정해 주지 않으면, 매번 실행할 때마다 값이 변경됨
- 테스트할 때마다 값이 변경되므로 비교 평가가 불가함
- 따라서 seed를 지정해서 실험을 하고, 실제로 실행할 경우에는 이를 해제함
np.random.seed(0)
- random.randint(): 지정한 값 사이의 정수를 랜덤으로 생성
np.random.randint(10)
결과
7
np.random.randint(0,10,15)
결과
array([8, 0, 8, 5, 9, 3, 7, 1, 8, 2, 6, 1, 6, 2, 7])
- random.rand(): 0 이상 1 미만의 임의의 값을 생성
np.random.rand(10)
결과
array([0.35433176, 0.75517944, 0.15649 , 0.05942972, 0.22688245,
0.72483354, 0.64809509, 0.77758691, 0.34826044, 0.54150907])
np.random.rand(2,5)
결과
array([[0.08217991, 0.29054503, 0.45048709, 0.27329039, 0.37529013],
[0.53922297, 0.40800884, 0.26610577, 0.51821411, 0.95936814]])
1.2 실습
a = np.array([[1,2,3],[4,5,6]])
print(a)
결과
[[1 2 3]
[4 5 6]]
np.arange(10).reshape(2,5)
결과
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
np.arange(2,3,0.1)
결과
array([2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9])
np.linspace(1.0,4.0,6)
결과
array([1. , 1.6, 2.2, 2.8, 3.4, 4. ])
np.zeros((2,2),int)
결과
array([[0, 0],
[0, 0]])
np.zeros((2,2),float)
결과
array([[0., 0.],
[0., 0.]])
np.ones((2,2))
결과
array([[1., 1.],
[1., 1.]])
np.full((2,2), 7)
결과
array([[7, 7],
[7, 7]])
np.eye(2)
결과
array([[1., 0.],
[0., 1.]])
np.random.random((2,2))
결과
array([[0.42961291, 0.6709883 ],
[0.71483539, 0.01489149]])
1.3 배열 다루기
배열 모양 바꾸기
a = np.array([[1,2,3],[4,5,6]])
print(f'{a = }')
print(f'{a.reshape(-1) = }')
print(f'{a = }')
결과
a = array([[1, 2, 3],
[4, 5, 6]])
a.reshape(-1) = array([1, 2, 3, 4, 5, 6])
a = array([[1, 2, 3],
[4, 5, 6]])
- 배열은 변경 후 별도의 저장을 하지 않으면, 변경되지 않음
a_61 = a.reshape(-1)
print(f'{a_61 = }')
print(f'{a_61.shape = }')
print(f'{a = }')
결과
a_61 = array([1, 2, 3, 4, 5, 6])
a_61.shape = (6,)
a = array([[1, 2, 3],
[4, 5, 6]])
- 배열의 모양을 바꾸기 -> 열벡터로 변환 후 재배정함
a_32 = a.reshape(3,2)
print(a_32)
결과
[[1 2]
[3 4]
[5 6]]
2 인덱싱과 슬라이싱
2.1 인덱싱(Indexing)
- 배열에서 원소를 찾는 것
- 인덱스는 0부터 시작
- 맨 뒤는 -1
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
print('a = \n', a)
print(f'{a[2,2] = }')
print(f'{a[(2,2)] = }')
print(f'{a[1,2] = }')
print(f'{a[-1,-1] = }')
결과
a =
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
a[2,2] = 11
a[(2,2)] = 11
a[1,2] = 7
a[-1,-1] = 12
2.2 슬라이싱(Slicing)
- 배열에서 부분집합을 가져오는 것
- i:j -> i에서 (j-1)까지
print('a = \n', a)
print(f'{a[1,0:1] = }')
print(f'{a[1,:] = }')
print(f'{a[:,1] = }')
결과
a =
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
a[1,0:1] = array([5])
a[1,:] = array([5, 6, 7, 8])
a[:,1] = array([ 2, 6, 10])
print(f'{a[:2,:] = }')
결과
a[:2,:] = array([[1, 2, 3, 4],
[5, 6, 7, 8]])
print(f'{a[:2,1:3] = }')
print(f'{a[:,0:3:2] = }')
print(f'{a[:,-1:-4:-2]= }')
결과
a[:2,1:3] = array([[2, 3],
[6, 7]])
a[:,0:3:2] = array([[ 1, 3],
[ 5, 7],
[ 9, 11]])
a[:,-1:-4:-2]= array([[ 4, 2],
[ 8, 6],
[12, 10]])
print(f'{a[:,[3,0,2,1]] = }')
print(f'{a[[0,1,2],[0,1,2]] = }')
결과
a[:,[3,0,2,1]] = array([[ 4, 1, 3, 2],
[ 8, 5, 7, 6],
[12, 9, 11, 10]])
a[[0,1,2],[0,1,2]] = array([ 1, 6, 11])
print(f'{a = }')
a[0,0] = 100
print(f'{a = }')
결과
a = array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
a = array([[100, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
3 얕은 복사(shallow copy)와 깊은 복사(deep copy)
3.1 mutable과 immutable
- mutable : 배열에서 원소의 수정 가능한 자료형
- 리스트(List), 집합(Set), 딕셔너리(Dictionary)
- immutable : 배열에서 원소의 수정이 불가능한 자료형
- 문자열(String), 튜플(Tuple), Boolean, Number
mutable 동작원리
ls = [1,2,3]
arr = np.array(ls)
print(f'{ls = }')
print(f'{arr = }')
print(f'{id(ls) = }')
print(f'{id(arr) = }')
결과
ls = [1, 2, 3]
arr = array([1, 2, 3])
id(ls) = 2448791471360
id(arr) = 2448738516496
- 변수의 값을 변경하더라도 변수의 주소는 동일하고 배열의 값만 바뀜
ls[0] = 10
arr[0] = 100
print(f'{ls = }')
print(f'{arr = }')
print(f'{id(ls) = }')
print(f'{id(arr) = }')
결과
ls = [10, 2, 3]
arr = array([100, 2, 3])
id(ls) = 2448791471360
id(arr) = 2448738516496
ls = [4,5,6]
print(f'{ls = }')
print(f'{arr = }')
print(f'{id(ls) = }')
print(f'{id(arr) = }')
결과
ls = [4, 5, 6]
arr = array([100, 2, 3])
id(ls) = 2448791484224
id(arr) = 2448738516496
arr = np.array([4,5,6])
print(f'{ls = }')
print(f'{arr = }')
print(f'{id(ls) = }')
print(f'{id(arr) = }')
결과
ls = [4, 5, 6]
arr = array([4, 5, 6])
id(ls) = 2448791484224
id(arr) = 2448791602448
3.2 얕은 복사(shallow copy)
arr = np.array([1,2,3])
print(f'{arr = }')
print(f'{id(arr) = }')
arr_shallow_copied = arr
print(f'{arr_shallow_copied = }')
print(f'{id(arr_shallow_copied) = }')
결과
arr = array([1, 2, 3])
id(arr) = 2448791602256
arr_shallow_copied = array([1, 2, 3])
id(arr_shallow_copied) = 2448791602256
- 두 변수는 동일한 주소를 가지고 있으므로, 하나의 값을 변경하면 다른 하나도 변경됨
arr[0] = 500
arr_shallow_copied[2] = 1000
print(f'{arr = }')
print(f'{arr_shallow_copied = }')
결과
arr = array([ 500, 2, 1000])
arr_shallow_copied = array([ 500, 2, 1000])
3.3 깊은 복사(deep copy)
- 이러한 현상을 해소하기 위해서는 deep copy를 해야함
arr = np.array([1,2,3])
print(f'{arr = }')
print(f'{id(arr) = }')
import copy
arr_deep_copied = copy.deepcopy(arr)
arr_copied = arr.copy()
print(f'{arr_deep_copied = }')
print(f'{id(arr_deep_copied) = }')
print(f'{arr_copied = }')
print(f'{id(arr_copied) = }')
결과
arr = array([1, 2, 3])
id(arr) = 2448791602832
arr_deep_copied = array([1, 2, 3])
id(arr_deep_copied) = 2448791602448
arr_copied = array([1, 2, 3])
id(arr_copied) = 2448791603024
arr[0] = 500
arr_deep_copied[2] = 1000
print(f'{arr = }')
print(f'{arr_deep_copied = }')
결과
arr = array([500, 2, 3])
arr_deep_copied = array([ 1, 2, 1000])
4 배열 연산하기
4.1 사칙연산
a = np.arange(9).reshape(3, 3)
a
결과
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
a+3
결과
array([[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
a+3.0
결과
array([[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.]])
a*3
결과
array([[ 0, 3, 6],
[ 9, 12, 15],
[18, 21, 24]])
a/3
결과
array([[0. , 0.33333333, 0.66666667],
[1. , 1.33333333, 1.66666667],
[2. , 2.33333333, 2.66666667]])
a**2
결과
array([[ 0, 1, 4],
[ 9, 16, 25],
[36, 49, 64]])
- 배열과 벡터의 연산(브로드캐스팅 : shape가 다른 배열 간에도 자동반복하여 연산이 가능하게 하는 것)
a = np.arange(9).reshape(3, 3)
b = np.array([100, 200, 300])
print(f'{a = }')
print(f'{b = }')
결과
a = array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
b = array([100, 200, 300])
a+b
결과
array([[100, 201, 302],
[103, 204, 305],
[106, 207, 308]])
a*b
결과
array([[ 0, 200, 600],
[ 300, 800, 1500],
[ 600, 1400, 2400]])
a = np.arange(9).reshape(3, 3)
print(f'{a = }')
c = np.arange(0,90,10).reshape(3, 3)
print(f'{c = }')
결과
a = array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
c = array([[ 0, 10, 20],
[30, 40, 50],
[60, 70, 80]])
a+c
결과
array([[ 0, 11, 22],
[33, 44, 55],
[66, 77, 88]])
a*c
결과
array([[ 0, 10, 40],
[ 90, 160, 250],
[360, 490, 640]])
4.2 메서드를 이용한 연산
- 배열은 일종의 클래스 오브젝트로서 자체 변수와 메서드를 가지고 있음
a = np.arange(9).reshape(3, 3)
a
결과
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
a.sum()
결과
36
a.sum(axis=0)
결과
array([ 9, 12, 15])
a.sum(axis=1)
결과
array([ 3, 12, 21])
print(f'{a.min()= }, {a.max()= }, {a.mean()= }, {a.std()= }, {a.var()= }')
결과
a.min()= 0, a.max()= 8, a.mean()= 4.0, a.std()= 2.581988897471611, a.var()= 6.666666666666667
4.3 numpy 함수를 이용한 연산
print('a = \n', a)
print('c = \n', c)
결과
a =
[[0 1 2]
[3 4 5]
[6 7 8]]
c =
[[ 0 10 20]
[30 40 50]
[60 70 80]]
np.sqrt(a)
결과
array([[0. , 1. , 1.41421356],
[1.73205081, 2. , 2.23606798],
[2.44948974, 2.64575131, 2.82842712]])
np.dot(a, c.transpose())
결과
array([[ 50, 140, 230],
[ 140, 500, 860],
[ 230, 860, 1490]])
np.dot(a, c.T)
결과
array([[ 50, 140, 230],
[ 140, 500, 860],
[ 230, 860, 1490]])
4.3-1 기타 유용한 배열 연산
찾기 및 추출
a = np.arange(9).reshape(3, 3)
print('a = \n', a)
결과
a =
[[0 1 2]
[3 4 5]
[6 7 8]]
a>5
결과
array([[False, False, False],
[False, False, False],
[ True, True, True]])
a[a>5]
결과
array([6, 7, 8])
(a>3)&(a<=7)
결과
array([[False, False, False],
[False, True, True],
[ True, True, False]])
a[(a>3)&(a<=7)]
결과
array([4, 5, 6, 7])
4.4 기타 함수
np.empty_like(a)
결과
array([[ 0, 1, 0],
[ 5570652, 1544, 0],
[ 768, 181, 572533794]])
np.tile(a, (3, 2))
결과
array([[0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5],
[6, 7, 8, 6, 7, 8],
[0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5],
[6, 7, 8, 6, 7, 8],
[0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5],
[6, 7, 8, 6, 7, 8]])
a = np.arange(6).reshape(2, 3)
b = np.arange(0,60,10).reshape(2, 3)
print('a = \n', a)
print('b = \n', b)
결과
a =
[[0 1 2]
[3 4 5]]
b =
[[ 0 10 20]
[30 40 50]]
np.vstack((a,b))
결과
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 0, 10, 20],
[30, 40, 50]])
np.hstack((a,b))
결과
array([[ 0, 1, 2, 0, 10, 20],
[ 3, 4, 5, 30, 40, 50]])
np.concatenate((a,b), axis=0)
결과
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 0, 10, 20],
[30, 40, 50]])
np.concatenate((a,b), axis=1)
결과
array([[ 0, 1, 2, 0, 10, 20],
[ 3, 4, 5, 30, 40, 50]])
np.concatenate((a,b), axis=None)
결과
array([ 0, 1, 2, 3, 4, 5, 0, 10, 20, 30, 40, 50])
np.r_[a,b]
결과
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 0, 10, 20],
[30, 40, 50]])
np.c_[a,b]
결과
array([[ 0, 1, 2, 0, 10, 20],
[ 3, 4, 5, 30, 40, 50]])
np.ravel(a, order='C')
결과
array([0, 1, 2, 3, 4, 5])
np.ravel(a, order='F')
결과
array([0, 3, 1, 4, 2, 5])