[9일차] 배열 데이터를 효과적으로 다루는 Numpy 패키지
목차
1. 배열 생성하기
2. 배열의 연산
3. 배열의 인덱싱과 슬라이싱
1. 배열 생성하기
0. Numpy 호출
: Numpy를 패키지에서 불러와서 별칭을 np로 설정
import numpy as np
1. 시퀀스 데이터로부터 배열 생성
arr_obj = np.array(seq_data)
import numpy as np
data1 = [0, 1, 2, 3, 4, 5]
a1 = np.array(data1)
a1
>>> array([0, 1, 2, 3, 4, 5])
(1) 실수가 혼합된 배열 생성
data2 = [0.1, 5, 4, 12, 0.5]
a2= np.array(data2)
a2
>>> array([ 0.1, 5. , 4. , 12. , 0.5])
➡ 정수인 다른 숫자들도 온점(.)이 뒤에 붙으면서 실수처럼 처리됐다.
(2) 배열의 속성 표현
a1.dtype
>>> dtype('int32')
a2.dtype
>>> dtype('float64')
(3) 데이터를 직접 넣어서 배열 객체 생성
np.array([0.5, 2, 0.01, 8])
>>> array([0.5 , 2. , 0.01, 8. ])
(4) 2차원 배열 생성 방법
np.array([[1,2,3],[4,5,6],[7,8,9]])
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
2. 범위를 지정해 배열 생성
arr_obj = np.arange([start,] stop [,step])
np.arange(0, 10, 2)
>>> array([0, 2, 4, 6, 8])
np.arange(1, 10) # step 생략
>>> array([1, 2, 3, 4, 5, 6, 7, 8, 9])
np.arange(5) #start, step 생략
>>> array([0, 1, 2, 3, 4])
(1) reshape를 추가해 1차 배열을 2차 배열로 변경하기
np.arange(12).reshape(4,3) #배열의 원소 개수와 reshape(m,n)의 m*n의 개수가 같아야 한다
>>> array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
#1부터 배열이 시작되게 하려면
np.arange(1,13).reshape(4,3)
>>> array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])
#1부터 1000까지 짝수만 20*25으로
np.arange(2,1001,2).reshape(20,25)
(2) ndarray.shape 배열의 형태 출력
b1 = np.arange(12).reshape(4,3)
b1.shape
>>> (4, 3)
- 1차원 배열인 경우
b2 = np.arange(5)
b2.shape
>>>(5, )
(3) 범위의 시작과 끝을 지정한 후, 데이터의 개수를 지정해 Numpy 배열을 생성
arr_obj = np.linspace(start,stop [, num])
# 0~pi 까지 동일한 간격으로 20개로 나누기
# 'np.pi'는 Numpy에서 π를 입력할 때 이용
np.linspace(0,np.pi, 20)
>>> array([0. , 0.16534698, 0.33069396, 0.49604095, 0.66138793,
0.82673491, 0.99208189, 1.15742887, 1.32277585, 1.48812284,
1.65346982, 1.8188168 , 1.98416378, 2.14951076, 2.31485774,
2.48020473, 2.64555171, 2.81089869, 2.97624567, 3.14159265])
#1부터 50까지 50번
np.linspace(1,50)
>>> array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13.,
14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25., 26.,
27., 28., 29., 30., 31., 32., 33., 34., 35., 36., 37., 38., 39.,
40., 41., 42., 43., 44., 45., 46., 47., 48., 49., 50.])
#0부터 50까지
np.linspace(0,51)
>>> array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.,
13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25.,
26., 27., 28., 29., 30., 31., 32., 33., 34., 35., 36., 37., 38.,
39., 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., 50.])
3. 특별한 형태의 배열
- zeros() 모든 원소가 0인 다차원 배열을 만들어준다.
np.zeros(10)
>>> array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
np.zeros((3,4))
>>> array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
- ones() 모든 원소가 1인 다차원 배열을 만들어준다.
np.ones(5)
>>> array([1., 1., 1., 1., 1.])
np.ones((3,5))
>>> array([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]])
- eye() : 단위행렬(Identity matrix) 생성
np.eye(3)
>>> array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
👀단위 행렬: n*n인 정사각형 행렬에서 주 대각선이 모두 1이고 나머지가 0인 행렬
4. 배열의 데이터 타입 변환
(1) 문자열이 원소인 Numpy 배열
np.array(['1.5', '0.62', '2', '3.14', '3.141592'])
>>> array(['1.5', '0.62', '2', '3.14', '3.141592'], dtype='<U8')
(2) Numpy 데이터의 형식
(3) astype() 배열의 형 변환
num_arr = str_arr.astype(float)
str_a1 = np.array(['1.567', '0.123', '5.123', '9', '8'])
num_a1 = str_a1.astype(float)
num_a1
>>> array([1.567, 0.123, 5.123, 9. , 8. ])
str_a1.dtype
>>> dtype('<U5')
num_a1.dtype
>>> dtype('float64')
👀 문자열을 정수로
str_a2 = np.array(['1', '3', '5', '7', '9'])
num_a2 = str_a2.astype(int)
num_a2
>>> array([1, 3, 5, 7, 9])
str_a2.dtype
>>> dtype('<U1')
num_a2.dtype
>>> dtype('int32')
👀 실수를 정수로
num_f1 = np.array([10,21,0.549, 4.75, 5.98])
num_i1 = num_f1.astype(int)
num_i1
>>> array([10, 21, 0, 4, 5])
num_f1.dtype
>>> dtype('float64')
num_i1.dtype
>>> dtype('int32')
5. 난수 배열의 생성
- rand.rand() 예
#2*3 형태로 출력
np.random.rand(2,3)
>>> array([[0.21528453, 0.71300004, 0.69764024],
[0.51306462, 0.22018718, 0.62818844]])
#랜덤으로 하나
np.random.rand()
>>> 0.620216720329649
#2개의 층을 가진 3*4
np.random.rand(2,3,4)
>>> array([[[0.98373438, 0.91075289, 0.50400202, 0.17318287],
[0.79773969, 0.40807503, 0.41524508, 0.27032026],
[0.36456861, 0.33602553, 0.00361297, 0.04439129]],
[[0.47685719, 0.92842377, 0.61546502, 0.18723697],
[0.00763824, 0.08685401, 0.57211559, 0.83891686],
[0.81909688, 0.10079134, 0.81381526, 0.80090411]]])
- rand.int() 예
np.random.randint(10, size=(3,4))
>>> array([[2, 6, 0, 8],
[4, 0, 7, 5],
[1, 8, 0, 5]])
np.random.randint(1, 30) # 사이즈를 지정하지 않으면 1
>>> 13
2. 배열의 연산
1. 기본 연산
: 배열의 형태가 같다면 연산이 가능
- 배열 2개 생성
arr1 = np.array([10, 20, 30, 40])
arr2 = np.array([1, 2, 3, 4])
- 두 배열의 합
arr1 + arr2
>>> array([11, 22, 33, 44])
- 두 배열의 차
arr1 - arr2
>>> array([ 9, 18, 27, 36])
- 배열에 상수 곱하기
arr2 * 2
>>> array([2, 4, 6, 8])
- 배열의 거듭제곱
arr2 ** 2
>>> array([ 1, 4, 9, 16], dtype=int32)
- 두 배열의 곱셈
arr1 * arr2
>>> array([ 10, 40, 90, 160])
- 복합 연산
arr1 / (arr2**2)
>>> array([10. , 5. , 3.33333333, 2.5 ])
- 비교 연산
arr1 > 20
>>> array([False, False, True, True])
2. 통계를 위한 연산
arr3 = np.arange(5)
arr3
>>> array([0, 1, 2, 3, 4])
(1) 합계 sum()과 평균 mean()
[arr3.sum(), arr3.mean()]
>>> [10, 2.0]
(2) 표준편차 std()와 분산 var()
- 표준편차 = 평균을 중심으로 퍼져있는 정도
- 분산 = 변랑이 평균으로부터 떨어져 있는 정도
[arr3.std(), arr3.var()]
>>> [1.4142135623730951, 2.0]
(3) 최솟값 min()과 최댓값 max()
[arr3.min(), arr3.max()]
>>> [0, 4]
(4) 누적 합 cumsum()과 누적 곱cumprod()
arr4 = np.arange(1,5)
arr4
>>> array([1, 2, 3, 4])
arr4.cumsum() # 누적 합
>>> array([ 1, 3, 6, 10], dtype=int32)
arr4.cumprod() # 누적 곱
array([ 1, 2, 6, 24], dtype=int32)
3. 행렬 연산
A = np.array([0, 1, 2, 3]).reshape(2,2)
A
>>> array([[0, 1],
[2, 3]])
B = np.array([3, 2, 0, 1]).reshape(2,2)
B
>>> array([[3, 2],
[0, 1]])
(1) 행렬곱 (matrix product) : 두개의 행렬에서 한 개의 행렬을 만들어내는 이항연산
- A.dot(B)
np.dot(A, B)
A.dot(B)
>>> array([[0, 1],
[6, 7]])
np.dot(A,B)
>>> array([[0, 1],
[6, 7]])
np.dot(B,A)
>>> array([[4, 9],
[2, 3]])
# 순서가 바뀌면 행렬 곱의 결과도 바뀐다.
(2) 전치 행렬 (traspose matrix) : 행과 열의 위치를 바꾸는 것
np.transpose(A)
>>> array([[0, 2],
[1, 3]])
A.transpose()
>>> array([[0, 2],
[1, 3]])
(3) 역행렬 : 행렬의 곱셈에 대한 역원
np.linalg.inv(A)
>>> array([[-1.5, 0.5],
[ 1. , 0. ]])
(4) 행렬식 (determinant) : 행렬식의 값이 0인 경우에는 역행렬을 가질 수 없다.
np.linalg.det(A)
>>> -2.0
3. 배열의 인덱싱과 슬라이싱
1. 배열의 인덱싱 : 배열의 위치나 조건을 지정해 배열의 원소를 선택하는 것
배열명[위치]
a1 = np.array([0, 10, 20, 30, 40, 50])
a1
>>> array([ 0, 10, 20, 30, 40, 50])
a1[0]
>>> 0
a1[4]
>>> 40
(1) 원소 변경하기
a1[5] = 70
a1
>>> array([ 0, 10, 20, 30, 40, 70])
(2) 1차원 배열에서 여러 개의 원소 선택하기
a1[[1,3,4]]
>>> array([10, 30, 40])
(3) 2차원 배열 생성
a2 = np.arange(10, 100, 10).reshape(3,3)
a2
>>> array([[10, 20, 30],
[40, 50, 60],
[70, 80, 90]])
a2[0,2]
>>> 30
(4) 2차원에서 원소 값 변경
a2[2,2] = 95
a2
>>> array([[10, 20, 30],
[40, 50, 60],
[70, 80, 95]])
(5) 하나만 입력하면 행위치를 지정한다.
a2[1]
>>> array([40, 50, 60])
(6) 2차원에서 특정 행을 변경
a2[1]=np.array([45,55,65])
a2
>>> array([[10, 20, 30],
[45, 55, 65],
[70, 80, 95]])
a2[1] = [47, 57, 67]
a2
>>> array([[10, 20, 30],
[47, 57, 67],
[70, 80, 95]])
(7) 2차원 배열에서 여러 원소 선택하기
배열명 [행위치1, 행_위치2, ..., 행위치[n]], [열_위치1, 열_위치2, ..., 열_위치n]]
a2[[0,2],[0,1]]
>>> array([10, 80])
(8) 배열 [조건]
a = np.array([1, 2, 3, 4, 5, 6])
a[a>3]
>>> array([4, 5, 6])
(9) 짝수만 출력
a[(a%2)==0]
>>> array([2, 4, 6])
2. 배열의 슬라이싱 : 범위를 지정해 배열의 일부분을 선택하는 슬라이싱
배열 [시작:끝]
b1=np.array([0, 10, 20, 30, 40, 50])
b1
>>> array([ 0, 10, 20, 30, 40, 50])
b1[:3]
>>> array([ 0, 10, 20])
b1[2:]
>>> array([20, 30, 40, 50])
(1) 슬라이싱으로 원소 변경
b1[2:5] = np.array([25,35,45])
b1
>>> array([ 0, 10, 25, 35, 45, 50])
b1[3:] =60
b1
>>> array([ 0, 10, 25, 60, 60, 60])
(2) 2차 배열에서의 슬라이싱
배열 [행시작: 행 끝, 열시작: 열 끝]
b2= np.arange(10, 100, 10).reshape(3,3)
b2
>>> array([[10, 20, 30],
[40, 50, 60],
[70, 80, 90]])
b2[1:3, 1:3]
>>> array([[50, 60],
[80, 90]])
b2[:3, 1:]
>>> array([[20, 30],
[50, 60],
[80, 90]])
(3) 행을 지정하고 열을 슬라이싱
b2[1][0:2]
>>> array([40, 50])
(4) 슬라이싱 된 배열에 값 지정하기
b2[0:2, 1:3] =np.array([[25, 35], [55, 65]])
b2
>>> array([[10, 25, 35],
[40, 55, 65],
[70, 80, 90]])