3.0 넘파이 배열 프로그래밍
1. 3장 넘파이 배열 프로그밍
- 이 장에서는 넘파이 패키지를 사용한 배열 프로그래밍에 대해 공부할 예정.
- 배열 프로그래밍은 대량의 데이터를 빠르게 조작하기 위한 필수적 과정이다.
- 파이썬의 데이터 관련 명령은 모두 넘파이 기능을 사용하므로 데이터 분석을위해서는
이 장에서 설명하는 모든 내용을 숙지해야한다.
2. 학습 목표
- 배열과 리스트의 차이점을 알고 배열을 사용하는 이유를 이해한다.
- 배열을 생성하고 다루는 방법을 익힌다.
- 넘파이를 사용하여 기술 통계를 낼 수 있다.
- 난수를 발생시키고 그 결과를 분석하는 방법을 공부한다.
3.1 넘파이 배열
1. 3.1 넘파이 배열
- 많은 숫자 데이터를 하나의 변수에 넣고 관리하는 리스트는 메모리 차지가 많고 속도가 느림.
- 이를 극복한게 배열(array)이다.
- 단, 리스트와 비슷하지만 두 가지 다른점이 있다.
- * 모든 원소가 같은 자료형이어야 한다.
- * 원소의 객수를 바꿀 수 없다.
- 파이썬 자체적으로 배열 자료형을 제공하지 않아서 배열을 사용할 수 있는 넘파이를 import 함.
2. 넘파이 패키지 임포트
- 배열을 사용하기 위해서 다음과 같이 임포트한다.
import numpy as np
3. 1차원 배열 만들기
- 넘파이 array 함수에 리스트를 널으면 ndarray 클래스 객체 즉, 배열로 변환해준다.
- 따라서 1 차원 배열을 만든는 방법은 다음과 같다.
ar = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
ar
# 결과 :
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
- 리스트와 비슷해 보이지만 type 명령으로 자료형을 살펴보면 ndarray임을 알 수 있다.
type(ar)
#결과 :
numpy.ndarray
- 리스트와 동일한 구조처럼 보임.
- 그러나 배열 객체와 리스트 객체는 많은 차이
- 우선 리스트 클래스 객체는 각각의 원소가 다른 자료형이 될 수 있음
- 하지만 배열 객체는 연속적인 메모리 배치를 가지기에 모든 원소가 같은 자료형이어야함.
- 대신 원소에 대한 접근과 반복문이 실행이 빨라짐
4. 백터와 연산
- 배열 객체는 배열의 각 원소에 대한 반복 연산을 하나의 명령어로 처리하는 벡터화 연산을 지원함.
- 예를 들어 다음처럼 여러개의 데이터를 모두 2배 해야하는 경우 생각해보자!
data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
answer = []
for di in data:
answer.append(2 * di)
answer
#결과 :
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
- 하지만 백터화 연산을 사용하면 다음과 같이 for문 없이 한번에 연산으로 할 수 있다.
- 계산속도도 빠르다.
x = np.array(data)
x
#결과 :
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
--------------------------------
x * 2
#결과:
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
# 참고로 일반 리스트 객체에 정수를 곱하면
# 객체의 크기가 정수배 만큼 증가한다.
L = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(2 * L)
# 결과
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- 백터화 연산은 비교 연산과 논리 연산을 포함한 모든 종류의 수학 연산에 대해 적용된다.
- 선형 대수에 적용되는 백터화 연산에 대해서는 나중에 살펴보자
a = np.array([1, 2, 3])
b = np.array([10, 20, 30])
2 * a + b
#결과 :
array([12, 24, 36])
a == 2
# 결과 :
array([False, True, False])
b > 10
# 결과 :
array([False, True, True])
(a == 2) & (b > 10)
# 결과 :
array([False, True, False])
- 2차원 배열의 행과 열의 갯수 구하기
# 행의 갯수
len(c)
# 정답 : 2
# 열의 갯수
len(c[0])
# 정답 : 3
5. 3차원 배열 만들기
- 리스트의 리스트의 리스트를 이용하면 3차원 배열도 생성 가능
- 크게를 나타낼 때는 가장 바깥쪽 리스트의 길이부터 가장 안쪽 리스트 길이의 순서로 표시
- 2 x 3 x 4 배열은 다음과 같이 만든다.
d = np.array([[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]],
[[11, 12, 13, 14],
[15, 16, 17, 18],
[19, 20, 21, 22]]]) # 2 x 3 x 4 array
- 3차원 배열의 깊이, 행, 열은 다음과 같이 구할 수 있다.
len(d), len(d[0]), len(d[0][0])
#결과
(2, 3, 4)
6. 배열의 차원과 크기 알아내기
- 배열의 차원 및 크기를 구하는 더 간단한 방법
- ndim 속성과 shape 속성을 이용
- ndim 속성 : 배열의 차원
- shape 속성 : 배열의 크기
# a = np.array([1, 2, 3])
print(a.ndim)
print(a.shape)
#결과
1
(3,)
# c = np.array([[0, 1, 2], [3, 4, 5]])
print(c.ndim)
print(c.shape)
#결과
2
(2, 3)
print(d.ndim)
print(d.shape)
#결과
3
(2, 3, 4)
7. 배열의 인덱싱
- 일차원 배열의 인덱싱은 리스트의 인덱싱과 같다
a = np.array([0, 1, 2, 3, 4])
a[2]
#결과
2
a[-1]
#결과
4
- 다차원 배열일 때는 다음과 같이 콤마(,)를 사용하여 접근할 수 있다.
- 콤마로 구분된 차원을 축(axis)이라고도 한다.
- 그래프 x축과 y축을 떠올리면 될 것.
a = np.array([[0, 1, 2], [3, 4, 5]])
a
#결과
array([[0, 1, 2],
[3, 4, 5]])
a[0, 0] # 첫 번째 행의 첫 번째 열
#결과
0
a[0, 1] # 첫 번째 행의 두 번째 열
#결과
1
a[-1, -1] # 마지막 행의 마지막 열
#결과
5
8. 배열 슬라이싱
- 배열 객체로 구현한 다차원 배열의 원소 중 복수 개를 접근하려면
일반적인 파이썬 슬라이싱(slicing)과 comma(,)를 함께 사용하면 된다.
a = np.array([[0, 1, 2, 3], [4, 5, 6, 7]])
a
#결과
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
a[0, :] # 첫번째 행 전체
#결과
array([0, 1, 2, 3])
a[:, 1] # 두번째 열 전체
#결과
array([1, 5])
a[1, 1:] # 두번째 행의 두번째 열부터 끝열까지
#결과
array([5, 6, 7])
a[:2, :2]
#결과
array([[0, 1],
[4, 5]])
# 연습문제
m = np.array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
# 이 행렬에서 값 7 을 인덱싱한다.
m[1, 2]
# 이 행렬에서 값 14 을 인덱싱한다.
m[2, 4]
# 이 행렬에서 배열 [6, 7] 을 슬라이싱한다.
m[1, 1:3]
# 이 행렬에서 배열 [7, 12] 을 슬라이싱한다.
m[1:, 2]
# 이 행렬에서 배열 [[3, 4], [8, 9]] 을 슬라이싱한다.
m[0, 3:5], m[1, 3:5]
#결과
(array([3, 4]), array([8, 9]))
9. 배열 인덱싱
- 넘파이 배열 객체의 또다른 강력한 기능은 팬시 인덱싱(Fancy indexing)이라고도 부르는 배열 인덱싱 방법이다.
- 인덱싱이라는 이름이 붙었지만 사실 데이터베이스의 질의(Query) 기능을 수행한다.
- 배열 인덱싱에서는 대괄호(Bracket [])안의 인덱스 정보로 숫자나 슬라이스가 아니라
위치 정보를 나타내는 또 다른 ndarray배열을 받을 수 있다.
- 여기에서는 배열을 편의상 인덱스 배열이라고 부르겠다.
- 배열 인덱싱의 방식에는 불리언(boolean) 배열 방식과 정수 배열 방식 두가지
- 다음은 짝수 사용법
a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
idx = np.array([True, False, True, False, True,
False, True, False, True, False])
a[idx]
#결과
array([0, 2, 4, 6, 8])
# 조건문 연산을 사용하면 간단하게 쓸 수 있다.
a % 2
#결과
array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1], dtype=int32)
a % 2 == 0
#결과
array([ True, False, True, False, True, False, True, False, True,
False])
a[a % 2 == 0]
#결과
array([0, 2, 4, 6, 8])
- 정수 배열 인덱싱에서는 인덱스 배열의 원소 각각이 원래
ndarray 객체 원소 하나를 가리키는 인덱스 정수이여야 한다.
- 예를 들어 1차원 배열에서 홀수번째 원소만 골라는 것은 다음과 같다
a = np.array([11, 22, 33, 44, 55, 66, 77, 88, 99])
idx = np.array([0, 2, 4, 6, 8])
a[idx]
#결과
array([11, 33, 55, 77, 99])
- 이 때 배열 인덱스의 크기가 원래 배열 크기와 달라도 상관없다.
- 반복해서 가리키는 경우에는 배열 인덱스가 더 커지기도 한다.
a = np.array([11, 22, 33, 44, 55 ,66, 77, 88 ,99])
idx = np.array([0, 0, 0, 2, 2, 4, 6, 6])
a[idx]
#결과
array([11, 11, 11, 33, 33, 55, 77, 77])
- 배열 인덱싱은 다차원 배열의 각 차원에 대해서도 할 수 있다.
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
a
#결과
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
a[:, [True, False, False, True]]
#결과
array([[ 1, 4],
[ 5, 8],
[ 9, 12]])
# 😂 이해x
a[[2, 0, 1], :]
#결과
array([[ 9, 10, 11, 12],
[ 1, 2, 3, 4],
[ 5, 6, 7, 8]])
# 연습문제
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
# 이 배열에서 3의 배수를 찾아라.
x[x % 3 == 0]
# 이 배열에서 4로 나누면 1이 남는 수를 찾아라.
x[x % 4 == 1]
# 이 배열에서 3으로 나누면
# 나누어지고 4로 나누면 1이 남는 수를 찾아라.
x[(x % 3 == 0) & (x % 4 == 1)]
'😀 기초 > 넘파이(NumPy)' 카테고리의 다른 글
3장 난수 발생과 카운팅(3.5) (0) | 2022.01.25 |
---|---|
3장 배열의 연산(3.3) (0) | 2022.01.25 |
3장 넘파이 배열의 생성과 변형(3.2) (0) | 2022.01.25 |
NumPy 한번에 끝내기 (0) | 2022.01.18 |