<목차>
1. 배열생성하기
2. 배열의 연산
3. 배열의 인덱싱과 슬라이싱
NumPy
: 다차원 배열 데이터를 효과적으로 처리할 수 있음
ㆍ 배열과 리스트?
- 파이썬에서 배열과 리스트 모두 인덱스 값 갖고 있음
- [ ]로 표시
ㆍ 리스트와 배열의 차이?//
- 배열 명확한 규칙성을 갖고 있음
- 배열 크기를 정확히 알고 있어 메모리 훨씬 효율적
- 배열 한계가 명확함(개수 안맞으면 에러)
- 배열은 배열간 연산이 가능함
리스트 +는 앞의 리스트에 뒤의 리스트 값을 연결함
- 배열은 배열 전체에 연산이 가능함
리스트의 *은 리스트의 요소를 반복함
- 리스트 원래는 인덱스 값이 없음(내 앞사람의 등을 잡는 방식으로 기억한다(pointer))
ㆍ배열과 튜플의 차이?
- 튜플은 변경, 삭제 어려움
- 배열은 그 범위를 뛰어넘는 값이 있다면 공간을 넓힘
01. 배열 생성하기
1) numpy 불러오기
- Numpy를 패키지에서 불러와서 별칭을 np로 설정
import numpy as np
2) 시퀀스 데이터로부터 배열 생성
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])
ㆍ정수와 실수가 혼합된 배열 생성
- 정수 실수 혼합되어 있을 경우 모두 실수로 변환
data2 = [0.1, 5, 4, 12, 0.5]
a2 = np.array(data2)
a2
>>> array([ 0.1, 5. , 4. , 12. , 0.5])
ㆍ 배열의 속성 표현 (ndarray.속성)
data1 = [0, 1, 2, 3, 4, 5]
a1 = np.array(data1)
a1.dtype
>>> dtype('int32')
data2 = [0.1, 5, 4, 12, 0.5]
a2 = np.array(data2)
a2.dtype
>>> dtype('float64')
※ 'int32' 'float64' ?
배열은 크기 지정해 가지고 있어 최대 문자수 지정
배열 메모리 효율적인 이유
ㆍ 데이터를 직접 넣어서 배열 생성 가능
np.array([0.5, 2, 0.01, 8])
>>> array([0.5 , 2. , 0.01, 8. ])
np.array([[1,2,3], [4,5,6], [7,8,9]]) #2차원 배열도 생성 가능
>>> np.array([[1,2,3], [4,5,6], [7,8,9]])
3) arrange: 범위를 지정해 배열 생성
arr_obj = np.arrange([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])
4) reshape(): 1차 배열을 2차배열로 변경
reshape(m,n) : m x n의 형태의 2차원 배열로 변경
※ 배열의 원소 개수와 reshape(m, n)의 m * n의 개수가 같아야 함
np.arange(12).reshape(4,3)
>>> array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
ㆍ 배열의 형태 출력 (ndarray.shape)
b1 = np.arange(12).reshape(4,3)
b1.shape
>>> (4, 3)
#1차원 배열의 경우
b2 = np.arange(5)
b2.shape
>>> (5,) #뒤에 안나와
5) linspace(): 범위의 시작과 끝을 지정하고 동일한 간격으로 개수만큼 나눈 배열을 생성
arr_obj = np.linspace(start, stop [,num]) (#num을 지정하지 않으면 50개)
# 0 ~ pi 까지 동일한 간격으로 10개로 나누기
np.linspace(0, np.pi, 10 ) # 'np.pi'는 Numpy에서 π를 입력할 때 이용
>>> array([0. , 0.34906585, 0.6981317 , 1.04719755, 1.3962634 ,
1.74532925, 2.0943951 , 2.44346095, 2.7925268 , 3.14159265])
6) 특별한 형태의 배열 생성
ㆍ 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))
>>> np.ones((3,5))
ㆍ eye() : 단위행렬 생성(n x n 정사각형 행렬에서 주 대각선이 모두 1이고 나머지가 0인 행렬)
np.eye(3)
>>> array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
7) astype(): 배열의 데이터 타입 변환
num_arr = arr.astype(dtype)
Numpy 배열 숫자뿐 아니라 문자열도 원소로 가질 수 있음
#문자열을 실수로
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')
#실수를 정수로
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')
7) random: 난수 배열의 생성
ㆍ rand() : 0과 1 사이의 실수 난수를 갖는 Numpy 배열 생성
rand_num = np.random.rand(d0, d1, d2, .....,dn)
np.random.rand(2,3)
>>> array([[0.46826822, 0.06670429, 0.34700295],
[0.78281807, 0.45567602, 0.56706535]])
np.random.rand()
>>> 0.943817939582156
np.random.rand(2,3,4) # z=층 y=행 x=열
>>> array([[[0.82252066, 0.0778985 , 0.86145235, 0.32814737],
[0.79310682, 0.24176504, 0.628546 , 0.81633578],
[0.84290595, 0.41124939, 0.02590378, 0.59567939]],
[[0.47073607, 0.81741497, 0.65395495, 0.19010422],
[0.15744914, 0.12794505, 0.72291499, 0.23141058],
[0.58288676, 0.27485333, 0.68207206, 0.98836223]]])
ㆍ randint(): [low, high] 사이의 정수 난수를 갖는 배열 생성
rand_num = np.random.randint([low,] high [,size])
np.random.randint(46, size=(3, 2))
>>> array([[45, 30],
[39, 16],
[ 3, 1]])
np.random.randint(1, 30) # 사이즈를 지정하지 않으면 1
>>> 20
02. 배열의 연산
1) 기본 연산
- 배열의 형태가 같다면 연산이 가능
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])
arr1 * arr2
>>> array([ 10, 40, 90, 160])
arr1 / arr2
>>> array([10., 10., 10., 10.])
arr2**2
>>> array([ 1, 4, 9, 16], dtype=int32)
#복합연산
arr1 / (arr2 ** 2)
>>> array([10. , 5. , 3.33333333, 2.5 ])
#비교연산
arr1 > 20 #각각의 원소별로 값 반환
array([False, False, True, True])
2) 통계를 위한 연산
ㆍ 합계sum()와 평균mean()
arr3 = np.arange(5)
arr3
>>> array([0, 1, 2, 3, 4])
[arr3.sum(), arr3.mean()]
>>> [10, 2.0]
ㆍ 표준편차std()와 분산var()
표준편차: 평균을 중심으로 퍼져있는 정도 (분산**1/2)
분산: 변량이 평균으로 부터 떨어져있는 정도
(표준편차와 분산이 평균으로부터 가까울 수록 신뢰도가 높다)
[arr3.std(), arr3.var()]
>>> [1.4142135623730951, 2.0]
ㆍ 최솟값min()과 최댓값max()
[arr3.min(), arr3.max()]
>>> [0, 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]])
ㆍ 행렬곱
: 두 개의 행렬에서 한 개의 행렬을 만들어내는 이항연산
A.dot(B)
>>> array([[0, 1],
[6, 7]])
np.dot(A,B)
>>> array([[0, 1],
[6, 7]])
B.dot(A) #어떤 게 기준이 되는지에 따라 값이 다름
>>> array([[4, 9],
[2, 3]])
ㆍ 전치행렬
: 행과 열의 위치를 바꾸는 것(대각선을 기준으로 바꿈)
np.transpose(A)
>>> array([[0, 2],
[1, 3]])
A.transpose()
>>> array([[0, 2],
[1, 3]])
ㆍ 역행렬
: 행렬의 곱셈에 대한 역원 (단위행렬이 되게 하는 값)
np.linalg.inv(A)
>>> array([[0, 2],
[1, 3]])
ㆍ 행렬식
: 행렬식의 값이 0인 경우에는 역행렬을 가질 수 없다. (det A = ad - bc = 0이면 A의 역행렬은 존재하지 않는다.)
np.linalg.det(A)
>>> -2.0
03. 배열의 인덱싱과 슬라이싱
인덱싱
: 배열의 위치나 조건을 지정해 배열의 원소를 선택하는 것
1) 1차원 배열의 인덱싱
ㆍ원소값 선택 및 변경
배열명[위치1, 위치2,...,위치n]
a1 = np.array([0,10,20,30,40,50])
a1
>>> array([ 0, 10, 20, 30, 40, 50])
#원소 가져오기
a1[0]
>>> 0
# 원소 변경하기
a1[5] = 70
a1
>>> array([ 0, 10, 20, 30, 40, 70])
#1차원 배열에서 여러 개의 원소 선택하기
a1[1,3,4]
>>> array([10, 30, 40])
2) 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
a2[1,2]
>>> 60
#원소 값 변경하기
a2[2,2] = 95
>>> array([[10, 20, 30],
[47, 57, 67],
[70, 80, 95]])
ㆍ 특정 행 변경
* 하나만 입력하면 행위치를 지정함
a2 = np.arange(10,100,10).reshape(3,3)
a2
>>> array([[10, 20, 30],
[40, 50, 60],
[70, 80, 90]])
a2[1]
>>> array([40, 50, 60])
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]])
ㆍ여러 원소 선택하기
배열명 [행위치1, 행위치2,..행위치[n]], [열_위치1, 열위치2,...,열위치[n]]
※ [행위치1, 열위치1], 아님 주의!!
a2[2,2] = 95
a2
>> array([[10, 20, 30],
[47, 57, 67],
[70, 80, 95]])
a2[[0,2],[0,1]]
>>> array([10, 80])
a2[[0,2],[0,2]]
>>> array([10, 95])
ㆍ조건에 따른 배열
배열명[조건]
a = np.array([1,2,3,4,5,6,0])
a[a > 3] #value 값
>>> array([4, 5, 6])
a[(a % 2) == 0]
>>> array([2, 4, 6, 0])
슬라이싱
: 범위를 지정해 배열의 일부분을 선택
1) 1차원 배열의 슬라이싱
배열[시작_위치:끝_위치
※ 범위 끝위치-1
b1 = np.array([0,10,20,30,40,50])
b1[1:4]
>>> array([10, 20, 30])
b1[:3]
>>> array([ 0, 10, 20])
ㆍ슬라이싱으로 원소 변경
b1 = array([ 0, 10, 25, 35, 45, 50])
b1[2:5] = np.array([25,35,45])
b1
>>> array([ 0, 10, 25, 35, 45, 50])
b1[3:6] = 60 #같은 값으로 변경
b1
>>> array([ 0, 10, 25, 60, 60, 60])
2) 2차원 배열 슬라이싱
:배열[행_시작_위치:행_끝_위치, 열_시작_위치:열_끝_위치]
※ 범위는 끝 위치 -1
ㆍ 행.열 슬라이싱
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]])
ㆍ 행을 지정하고 열을 슬라이싱
b2 = array([[10, 20, 30],
[40, 50, 60],
[70, 80, 90]])
b2[1][0:2]
>>> array([40, 50])
ㆍ 슬라이싱된 배열에 값 지정하기
b2[0:2, 1:3] = np.array([[25,35], [55,65]])
b2
>>> array([[10, 25, 35],
[40, 55, 65],
[70, 80, 90]])
'MLOps 개발자 양성과정 > python' 카테고리의 다른 글
[Day-3] 제어문 (0) | 2023.01.15 |
---|---|
[Day-4] 입력과 출력 (0) | 2023.01.11 |
[Day-12] 데이터 분석을 위한 패키지-2 (pandas) (0) | 2023.01.09 |
[Day-2] 변수와 자료형 (0) | 2023.01.08 |
[Day-1] 파이썬을 계산기처럼 이용하기 (0) | 2023.01.08 |