REMI Lab
OPEN KNOWLEDGE / COURSES

11주차 · NumPy 기초 입문

이 페이지의 내용

학습 목표

이 장을 마치면 다음을 할 수 있습니다.

  • import numpy as np와 np.array(...)의 의미를 설명한다.
  • NumPy의 기본 자료구조 ndarray를 “shape가 있는 숫자 배열”로 이해한다.
  • ndim, shape, size, dtype로 배열을 점검한다.
  • np.array, np.zeros, np.ones, np.arange, np.linspace로 배열을 만든다.
  • 1D/2D 배열에서 인덱싱, 슬라이싱, 불리언 마스크를 사용한다.
  • reshape와 np.newaxis로 (3,), (1, 3), (3, 1)의 차이를 확인한다.
  • 원소별 연산 *와 행렬곱 @를 구분한다.
  • axis=0, axis=1 방향으로 합계와 평균을 계산한다.
  • 브로드캐스팅(broadcasting)이 되는 경우와 실패하는 경우를 설명한다.
  • 원본을 함께 보는 배열(view)과 별도 복사본(copy)의 차이를 알고 원본 변경 위험을 피한다.

0. 예제 코드에서 >>>가 보이면

NumPy 예제를 찾아보다 보면 다음처럼 >>>가 붙은 코드를 볼 수 있습니다.

>>> import numpy as np
>>> np.array([1, 2, 3])
array([1, 2, 3])

여기서 >>>는 Python 대화형 프롬프트입니다. 실제 코드에 붙이지 않습니다.

# 실제 코드에는 이렇게 씁니다.
import numpy as np
arr = np.array([1, 2, 3])
print(arr)

1. NumPy 빠르게 시작하기: 기본 습관 네 가지

NumPy 코드는 보통 아래처럼 시작합니다.

import numpy as np
arr = np.array([1, 2, 3], dtype=float)
print(arr.shape)
print(arr * 2)

처음에는 네 가지를 고정 습관으로 두세요.

  1. import numpy as np로 NumPy를 불러온다.
  2. np.array([...])로 리스트를 배열로 바꾼다.
  3. 계산 전 shape, dtype를 확인한다.
  4. arr * 2, arr + arr는 원소별 연산임을 기억한다.
예제 1 · NumPy 첫 배열 코드를 실행하고 출력 결과를 확인하세요.
Ready

2. ndarray란 무엇인가요?

NumPy의 핵심 자료구조는 ndarray입니다. 이름 그대로 N-dimensional array, 즉 여러 차원을 담는 배열입니다.

차원수학적 느낌NumPy 예shape
0D스칼라처럼 보이는 값np.array(3.3)()
1D숫자 줄, 벡터처럼 사용np.array([1, 2, 3])(3,)
2D행렬, 표np.array([[1, 2], [3, 4]])(2, 2)

3. list와 ndarray: 같은 기호도 의미가 다릅니다

Python 리스트와 NumPy 배열은 모두 값을 담을 수 있지만, 연산 의미가 다릅니다.

코드Python listNumPy ndarray
a + b이어붙이기원소별 덧셈
a * 2리스트 반복원소별 곱셈
shape없음있음
dtype공통 dtype 없음배열 전체의 자료형을 명시적으로 관리
a = [1, 2, 3]
b = [10, 20, 30]
print(a + b) # [1, 2, 3, 10, 20, 30]
print(a * 2) # [1, 2, 3, 1, 2, 3]
예제 2 · list와 ndarray 연산 비교 코드를 실행하고 출력 결과를 확인하세요.
Ready

4. 배열을 만드는 기본 도구

처음 실습에서 자주 쓰는 배열 생성 함수를 정리하면 다음과 같습니다.

함수역할예
np.array(data)직접 값을 넣어 배열 생성np.array([1, 2, 3])
np.zeros(shape)0으로 채운 배열np.zeros((2, 3))
np.ones(shape)1로 채운 배열np.ones((2, 3))
np.arange(start, stop, step)일정 간격 숫자np.arange(0, 10, 2)
np.linspace(start, stop, num)구간을 num개로 균등 분할np.linspace(0, 1, 5)
예제 3 · 배열 생성 함수 코드를 실행하고 출력 결과를 확인하세요.
Ready

5. 배열 건강검진 4종: ndim, shape, size, dtype

계산 전에 아래 네 가지를 확인하면 많은 오류를 미리 막을 수 있습니다.

속성뜻예
ndim축의 개수, 차원 수2D 배열이면 2
shape각 축의 길이(3, 4)
size전체 원소 개수12
dtype원소 자료형float64, int64
shape가 (3, 4)이면 size는 3 × 4 = 12입니다.
예제 4 · ndim, shape, size, dtype 코드를 실행하고 출력 결과를 확인하세요.
Ready

6. 인덱싱과 슬라이싱: 원하는 칸, 행, 열 꺼내기

1D 배열

a = np.array([10, 20, 30, 40])
print(a[0]) # 첫 번째 값 10
print(a[1:3]) # index 1부터 3 직전까지 → [20 30]
print(a[-1]) # 마지막 값 40

2D 배열

A = np.array([
[1, 2, 3],
[4, 5, 6],
])
print(A[0, 0]) # 1행 1열, NumPy index로는 [0, 0]
print(A[1, 2]) # 2행 3열 → 6
print(A[0, :]) # 첫 번째 행 전체
print(A[:, 1]) # 두 번째 열 전체
코드의미
A[row, col]특정 칸 하나
A[row, :]특정 행 전체
A[:, col]특정 열 전체
A[start:stop]start부터 stop 직전까지
예제 5 · 2D indexing과 slicing 코드를 실행하고 출력 결과를 확인하세요.
Ready

7. reshape와 np.newaxis: 1D를 행/열 모양으로 바꾸기

10주차에서 보았듯이 (3,), (1, 3), (3, 1)은 다릅니다. 지금부터는 같은 숫자라도 shape가 달라지면 NumPy가 다르게 해석할 수 있다는 점을 확인합니다.

(3,) → 축이 하나인 길이 3 배열
(1, 3) → 1행 3열
(3, 1) → 3행 1열

reshape는 전체 원소 개수를 유지하면서 모양을 바꿉니다.

a = np.arange(6)
print(a.shape) # (6,)
print(a.reshape(2, 3))
print(a.reshape(3, 2))

np.newaxis는 새 축을 하나 추가합니다.

v = np.array([10, 20, 30])
print(v[:, np.newaxis].shape) # (3, 1)
print(v[np.newaxis, :].shape) # (1, 3)
예제 6 · reshape와 newaxis 코드를 실행하고 출력 결과를 확인하세요.
Ready

8. 원소별 연산과 행렬곱 구분하기

NumPy에서 +, -, *, /는 기본적으로 같은 위치 원소끼리 계산합니다.

A + B # 원소별 덧셈
A * B # 원소별 곱셈, 행렬곱 아님

10주차에서 행렬곱은 행과 열이 만나 만드는 계산이라고 배웠습니다. NumPy에서는 이 계산을 @로 씁니다.

A @ x
A @ B
인터랙티브 · 10주차의 Ax 계산 다시 보기 값을 바꾸며 계산 규칙을 눈으로 확인하세요.

행렬-벡터 곱은 행렬의 각 행이 벡터와 만나 결과 숫자 하나씩을 만드는 계산입니다.

예제 7 · *와 @ 비교 코드를 실행하고 출력 결과를 확인하세요.
Ready
인터랙티브 · NumPy shape와 연산 가능 여부 값을 바꾸며 계산 규칙을 눈으로 확인하세요.

인터랙티브 · A @ B가 한 칸씩 채워지는 과정 값을 바꾸며 계산 규칙을 눈으로 확인하세요.

결과의 한 칸은 앞 행렬의 한 행과 뒤 행렬의 한 열을 같은 위치끼리 곱해 더한 값, 즉 내적입니다.


9. axis별 집계: 어느 축을 접어 모으나요?

2D 배열에서 합계나 평균을 구할 때 axis를 지정할 수 있습니다.

arr.sum(axis=0) # 0번 축(행 인덱스 방향)을 내려가며 모음 → 열별 결과가 남음
arr.sum(axis=1) # 1번 축(열 인덱스 방향)을 옆으로 모음 → 행별 결과가 남음

말이 헷갈리면 “어느 축을 없애서 결과가 무엇으로 남는가”를 생각하세요.

원래 shape코드결과 개수의미
(3, 4)sum(axis=0)4개행 인덱스 방향으로 내려가며 합쳐서 열별 결과가 남음
(3, 4)sum(axis=1)3개열 인덱스 방향으로 옆으로 합쳐서 행별 결과가 남음
인터랙티브 · axis=0과 axis=1 방향 확인 값을 바꾸며 계산 규칙을 눈으로 확인하세요.

예제 8 · axis별 sum과 mean 코드를 실행하고 출력 결과를 확인하세요.
Ready

10. 브로드캐스팅(broadcasting): NumPy가 모양을 맞춰 주는 경우

수학 교과서의 행렬 덧셈은 보통 같은 크기끼리만 가능합니다. NumPy는 일부 경우에 작은 배열을 필요한 방향으로 반복해 큰 배열과 계산하게 해 줍니다. 이것을 브로드캐스팅(broadcasting)이라고 합니다.

인터랙티브 · 브로드캐스팅 성공과 실패 값을 바꾸며 계산 규칙을 눈으로 확인하세요.

쉬운 규칙

아무 모양이나 자동으로 맞춰 주는 것은 아닙니다. NumPy는 뒤쪽 축부터 shape를 비교합니다. 각 축이 다음 중 하나면 브로드캐스팅이 가능합니다.

  1. 두 길이가 같다.
  2. 둘 중 하나가 1이다.
  3. 앞쪽에 없는 축은 길이 1처럼 본다.
  4. 스칼라 shape ()는 모든 shape와 호환된다.

예:

A.shape # (2, 3)
row.shape # (3,)
A + row # 가능: row가 각 행에 반복됨
col.shape # (2, 1)
A + col # 가능: 각 행의 보정값이 옆으로 반복됨

실패 예:

A.shape # (2, 3)
bad.shape # (2,)
A + bad # 실패: 마지막 축 3과 2가 맞지 않음
예제 9 · broadcasting으로 센서 보정값 더하기 코드를 실행하고 출력 결과를 확인하세요.
Ready

11. 불리언 마스크(boolean mask): 조건에 맞는 원소만 고르기

불리언 마스크는 각 원소가 조건을 만족하는지를 True/False로 나타내는 배열입니다.

data = np.array([3.0, 7.5, 1.2, 9.8])
mask = data > 5.0
print(mask) # [False True False True]
print(data[mask]) # [7.5 9.8]

여러 조건을 묶을 때는 괄호와 &, |를 사용합니다.

normal = (data >= 0.0) & (data <= 10.0)

2D 배열에 2D 마스크를 적용하면 조건을 만족한 값만 뽑혀 1D 배열로 나옵니다. 예를 들어 corrected[mask]는 정상 범위에 들어온 값만 한 줄로 모은 배열입니다.

예제 10 · 불리언 마스크로 정상 범위 필터링 코드를 실행하고 출력 결과를 확인하세요.
Ready

12. 원본을 함께 보는 배열과 별도 복사본

NumPy에서 기본 slicing(arr[1:3])은 새 배열처럼 보이지만, 실제로는 원본 데이터를 함께 바라보는 view일 수 있습니다. view를 수정하면 원본도 바뀝니다.

반대로 불리언 마스크(arr[mask])나 정수 배열 인덱싱은 보통 별도 복사본을 만듭니다. 그래서 “잘라 낸 배열이 원본과 연결되어 있는가?”는 선택 방식에 따라 달라질 수 있습니다.

예제 11 · 원본과 복사본 차이 코드를 실행하고 출력 결과를 확인하세요.
Ready

13. 종합 예제: 2D 센서 배열 처리

아래 예제는 이번 주 내용을 한 번에 묶습니다.

  • 3일 × 4회 측정값 배열 생성
  • shape 건강검진
  • 센서 보정값 브로드캐스팅
  • axis별 평균
  • 불리언 마스크로 정상 범위 비율 계산
종합 예제 · 2D 센서 데이터 처리 코드를 실행하고 출력 결과를 확인하세요.
Ready

종합 예제 해설

  1. voltage.shape == (3, 4)이므로 3일, 4회 측정 표로 읽을 수 있습니다.
  2. offset.shape == (4,)인 보정값은 각 행에 반복 적용됩니다. 이것이 브로드캐스팅입니다.
  3. mean(axis=1)은 1번 축, 즉 열 인덱스 방향으로 옆으로 모아 일별 평균을 만듭니다.
  4. mean(axis=0)은 0번 축, 즉 행 인덱스 방향으로 내려가며 같은 측정 회차끼리 모아 회차별 평균을 만듭니다.
  5. 불리언 마스크는 정상 범위에 들어오는 칸을 True로 표시합니다.

실습 문제 · 직접 코딩

이번 주 실습은 “계산 결과”보다 shape와 해석 문장을 함께 출력하는 것이 중요합니다.

목표: 배열을 만들고 ndim, shape, size, dtype를 확인합니다.

완료 조건: size == shape[0] * shape[1] 검증을 통과하고, 배열이 몇 행 몇 열인지 한 문장으로 출력하세요.

실습 1 · 배열 건강검진 코드를 실행하고 출력 결과를 확인하세요.
Ready

제출 전 자기점검

  • import numpy as np를 사용했는가?
  • 계산 전 ndim, shape, size, dtype 중 최소 2개 이상 확인했는가?
  • *와 @의 차이를 설명할 수 있는가?
  • (3,), (1, 3), (3, 1)의 차이를 말할 수 있는가?
  • axis=0, axis=1 결과가 몇 개 나오는지 예측했는가?
  • 브로드캐스팅이 성공한 이유 또는 실패한 이유를 shape로 설명했는가?
  • mask 조건을 괄호와 &/|로 작성했는가?
  • 원본을 보존해야 하는 slice에는 .copy()가 필요한지 생각했는가?
Back to top ↑