SK플래닛 ai활용 데이터엔지니어 과정 2기/데이터 처리

데이터 처리 1 - Numpy

dev-lee 2026. 5. 13. 09:18

1. 데이터 처리 / 준비 / Transform

데이터 품질을 향상시키기 위해 도메인과 최종 산출물에 적합한 형태로 데이터를 가공하는 단계. 데이터의 형태, 규모, 싱글/분산, 메모리 환경 등에 따라 적절한 도구를 선택해야 함.

1.1 도구 별 특징

라이브러리 특징  베이스 언어 데이터 규모
numpy ndarray(다차원배열) 중심 수치 계산, 데이터 분석/처리의 근간 C 기반 연산 소~중규모
pandas Series(1D), DataFrame(2D) 자료구조. 파이썬 데이터 분석 표준. 데이터를 한 번에 메모리에 로드 Python + Cython + C (Single Core) 중규모 (~ 수 GB)
polars DataFrame, 지연처리 기반 최적화, 스트리밍/병렬처리 집중 Rust / Apache Arrow 대규모 (~ 수십 GB)
spark RDD/DataFrame/DataSet, 분산처리 프레임워크. 클러스터 기반 작동 Scala/Java/PySpark/RSpark 초대규모 (~ TB 이상)

처리해야 하는 데이터의 크기에 따라 도구를 잘 판단해 선택해야 함.


2. NumPy 개요

2.1 학습 포인트

  • 데이터 → ndarray 변환 — 입력 데이터를 ndarray로 처리하는 흐름을 잘 이해해야 함
  • 스칼라/벡터 연산 — 연산 단위에 집중할 필요가 있음
  • 속도 특성 — 파이썬 리스트보다 빠른 이유를 기억해두면 좋음
  • 상위 라이브러리의 베이스 — pandas, polars 등 대부분의 라이브러리가 numpy 기반
  • 인덱싱 기법 — 다양한 인덱싱 방식 체크 필요

2.2 특징

  • 속도 — 파이썬 리스트보다 최대 50배 빠름
  • 용도 — 대규모 다차원 배열과 행렬 연산을 효율적으로 처리하는 핵심 과학 계산 라이브러리
  • 활용 영역 — 수치 계산 분야의 필수, 머신러닝/딥러닝의 기반 기술
  • 공식 표현 — The fundamental package for scientific computing with Python

2.3 자료구조

  • ndarray — n차원의 배열
  • 타입 동일성 — 배열의 모든 구성원의 타입은 동일해야 함

3. NumPy 기본

# Colab(.ipynb) 환경에서 구동
import numpy as np

np.__version__   # '2.0.2'

# np 모듈에 존재하는 함수/변수 개수 확인
len(dir(np))     # 약 532개
  • import np — numpy의 관용적 alias
  • dir(np) — 모듈 내 함수/변수 전체 확인

4. 배열 생성

4.1 생성 방식

  • 기본 패턴 — 입력원(Raw Data)으로부터 생성
  • 입력원 종류 — 리스트, 튜플, 다른 배열, Series, DataFrame, csv 등
  • 출력 — ndarray
  • 빈 배열(버퍼) — 값을 미리 채우지 않은 형태도 생성 가능

4.2 array() — 리스트로부터 배열 생성

datas = [1, 2, 3]
arr = np.array(datas)

arr, arr.shape, type(arr), arr.ndim, arr.dtype
# (array([1,2,3]), (3,), numpy.ndarray, 1, dtype('int64'))
  • shape — 튜플로 표현된 형태 정보 (3,)
  • type — numpy.ndarray
  • ndim — 차원 수
  • dtype — 데이터 타입. 정수 입력 시 기본 int64 적용
  • 타입 적정성 체크 — int64가 적절한지 메모리 효율 관점에서 검토 필요
# 2차원 리스트 -> 2차원 배열
datas = [
    [1, 2, 3],
    [4, 5, 6]
]
arr = np.array(datas)
# shape=(2,3), ndim=2, dtype=int64
  • 원본이 정수형이면 배열 타입은 int64 (값 1개당 8바이트 할당)

배열의 차원: 벡터(자연어 처리/벡터DB), 매트릭스(데이터 분석/ML), 스칼라·벡터 연산을 이해해야 행렬 연산까지 확장 가능.


4.3 asarray() — 카피 생성

깊은 카피 개념으로 원본과 분리된 새 배열을 생성.

arr2 = np.asarray(arr)

# 인덱싱 (차원 축소)
arr2[0]        # array([1, 2, 3])  -> 1차원
arr2[0][0]     # np.int64(1)       -> 0차원(스칼라)

# 수정 후 원본 확인
arr2[0][0] = 100
# arr2만 변경, arr은 유지됨
  • 인덱싱 1회 = 차원 축소 1회 — 2차원 → 1차원 → 스칼라
  • 깊은 카피 — 원본과 메모리 분리됨

4.4 arange() — 연속된 수로 배열 생성

np.arange(5)             # [0, 1, 2, 3, 4]
np.arange(0, 5, 1)       # 동일
np.arange(0, 5, 2)       # [0, 2, 4]
np.arange(0, 5, 0.5)     # [0., 0.5, ..., 4.5]
  • 기본 동작 — 시작값 <= x < 끝값 범위를 step 간격으로 구간화
  • 인자 — (시작, 끝, 간격)
# 차원 조정
np.arange(16).reshape(4, 4)
np.arange(16).reshape(8, -1)     # -1은 자동 계산
np.arange(16).reshape(2, -1, 4)
  • reshape 제약 — 1차원 수 × 2차원 수 × ... = 총 데이터 수 일치 필수
  • -1 지정 — 나머지 차원으로부터 자동 계산
  • 불일치 시 — 에러 발생 (reshape(4, 3) 같은 경우)

4.5 zeros / ones / empty — 특수 형태 배열

np.zeros((2, 3))   # 모든 원소 0, dtype=float64
np.ones((2, 3))    # 모든 원소 1, dtype=float64
np.empty((2, 3))   # 초기화되지 않은 메모리(특정값/랜덤)
  • 기본 dtype — float64
  • 용도 — 형태(shape)만 부여하고 값은 채워야 하는 경우, 버퍼 역할, 수학적 특수 연산용

4.6 zeros_like / ones_like / empty_like — 형태 복사

대상 배열의 shape을 복사하여 0/1/특정값으로 채움.

arr2 = np.ones_like(arr)
# arr과 동일한 shape에 1로 채워진 배열 생성
  • shape 복사 — 원본과 동일한 차원 구성
  • 활용 — 동일 크기의 보조 배열이 필요할 때

4.7 eye / identity — 단위 행렬

np.eye(3, 3)
np.identity(3)
# [[1, 0, 0],
#  [0, 1, 0],
#  [0, 0, 1]]

np.eye(3, 4)   # 비정방형도 가능
  • 대각선 1, 나머지 0 — 단위 행렬 구성
  • eye는 비정방형도 허용 — identity는 정방형만 가능

4.8 random — 정규분포 기반 난수

arr = np.random.randn(2, 3, 4)
# 표준편차 1, 평균 0인 정규분포 난수 생성

# 조건식 -> 불리언 배열
arr > 0
  • randn — 표준정규분포(평균 0, 표준편차 1) 난수 발생
  • 분포 범위 — 정규분포에 맞춰 자동 조정
  • 차원 확인 — 출력 시 대괄호 [[[ 개수로 차원 빠르게 판단 가능
  • 활용 — 임의 벡터/매트릭스 구성, DL 모델의 초기 파라미터(CNN 커널값), GAN의 노이즈 벡터 등

스칼라(0차원) vs 행렬(3차원) 연산 시, 스칼라가 모든 구성원을 방문해 비교/연산을 수행한 결과로 대체됨 (브로드캐스팅).


5. 기본 연산

5.1 배열 vs 스칼라

배열의 모든 구성원에 스칼라 값이 일일이 접근해 연산을 수행.

arr = np.random.randn(2, 3)

arr + 10
arr - 10
arr * 10
arr / 10
  • 모든 멤버 접근 후 연산 → 결과 대체 — pandas의 apply, 파이썬의 map과 유사한 동작

5.2 배열 vs 배열

동일 크기

같은 위치의 원소끼리 연산 수행.

arr + arr   # 같은 위치 원소 합
arr - arr   # 모두 0
arr * arr   # 같은 위치 원소 곱
arr / arr   # 모두 1
  • 요소별 연산(element-wise) — shape이 동일할 때 위치 기준으로 매칭

다른 크기 — 브로드캐스팅

연산이 가능하도록 차원을 자동 확장하여 처리.

  • 원칙 — 연산이 맞닿은 행/열이 일치하거나 1일 때만 가능
  • 조건 불충족 시 — 에러 발생
  • 메커니즘 — 부족한 차원을 스크래치(복제)하여 연산

6. 타입

배열 구성원을 메모리에 할당하려면 타입 지정이 필요. 배열 당 타입은 하나로 고유함.

6.1 유형

유형  종류
정수형 int8, int16, int32, int64 (기본)
부호 없는 정수형 uint8, uint16, uint32, uint64
실수형 float16, float32, float64 (기본)
복소수형 complex64, complex128
논리형 bool
객체형 문자열 등
  • 확인 방법 — 배열.dtype
  • float8은 없음 — 실수형은 16부터 시작
arr = np.array([1, 2, 3])
arr.dtype                              # dtype('int64')

arr = np.array([1, 2, 3], dtype=np.uint8)
arr.dtype                              # dtype('uint8')

명시적 형변환은 데이터 손실 가능, 암묵적 형변환은 손실은 없되 메모리 낭비 가능.


6.2 astype() — 타입 변경

arr = np.array([1, 2, 256])
# (array([1, 2, 256]), dtype('int64'))

tmp = arr.astype(np.int8)
# (array([1, 2, 0], dtype=int8), dtype('int8'))
  • int64 → int8 — 8바이트 → 1바이트, 7바이트 정보 손실
  • 256 → 0 변환 이유 — int8은 1바이트(8비트)만 보유하므로 상위 비트가 잘려나감
  • 비트 표현 — 0...0100000000 (256) → 하위 8비트 00000000만 남음 → 0
  • 257이었다면 — 0...0100000001 → 00000001 → 1 보존

7. 데이터 추출

7.1 인덱싱

배열[인덱스] 형태로 접근. 차원 축소 개념.

arr = np.arange(1, 7).reshape((2, 3))
# [[1, 2, 3],
#  [4, 5, 6]]

arr[0]         # array([1, 2, 3])     -> 2D -> 1D
arr[0][-1]     # np.int64(3)          -> 1D -> 0D
arr[0, -1]     # np.int64(3)          -> 좌표 표기
  • 인덱싱 1회 = 차원 축소 1회
  • 좌표 표기 — [0, -1]처럼 차원별 인덱스를 쉼표로 분리

7.2 슬라이싱

배열[시작:끝:간격] 형태로 추출. 차원 유지 개념.

arr2 = arr[:]              # 전체 카피
arr2[0] = 100              # 0번 행 전체 100으로 일괄 처리

arr = np.arange(16).reshape(2, -1)
arr[:, :]                  # 원본 카피 (양쪽 차원 전부)
arr[:1, :1]                # array([[0]])  -> 2차원 유지
arr[:1, 0]                 # array([0])    -> 1회 차원 축소
  • : 단독 — 해당 차원 전체 선택
  • 슬라이싱은 차원 유지 — 결과가 단일 원소여도 배열 형태로 보존
  • 결측치 처리 패턴 — arr2[0] = 100처럼 슬라이싱 후 일괄 대입

7.3 불리언 인덱싱

조건식의 불리언 결과를 활용해 만족 데이터를 추출/필터링.

arr = np.random.randn(4, 10)

# 음수를 결측치로 가정 -> 0으로 치환
arr[arr < 0] = 0
  • 조건식 결과 — 불리언 배열로 반환됨
  • 활용 패턴 — arr[조건] = 값 형태로 대상 특정 후 변경
  • pandas 대응 — fillna 등 매개변수 기반 기능과 유사한 흐름

데이터 분석에서 가장 빈번하게 사용하는 패턴 중 하나.


7.4 팬시 인덱싱

데이터의 위치를 직접 지정해 추출. 방향성/연속성 없이 임의 순서 추출 가능.

arr = np.arange(32).reshape(-1, 4)

arr[[3, 0, 4, 5]]
# 3행, 0행, 4행, 5행 순으로 추출

arr[[3, 0, 4, 5], [2, 1, 0, 3]]
# 차원별 인덱스 지정 -> array([14, 1, 16, 23])
  • 임의 순서 추출 — 인덱스 리스트로 원하는 순서대로 선택
  • 차원별 좌표 추출 — 각 차원의 인덱스를 리스트로 매칭
  • pandas 계승 — iloc이 이 개념을 상속함

8. 배열 함수

8.1 메타 정보 및 변형

arr.copy()                    # 깊은 카피

# 메타 정보 확인
arr.shape, arr.dtype, arr.ndim

# 축 변환
arr.T, arr.T.shape            # 전치
arr.transpose((1, 0))         # 차원 인덱스 지정

# 차원 변환
arr = arr.reshape((2, 2, 8))
arr.transpose((1, 2, 0))      # 다차원 축 변경
  • shape / dtype / ndim — 메모리 로드 후 가장 먼저 파악할 메타 정보
  • T / transpose — 차원 위치 인덱스로 변경 가능
  • 활용 — 각종 알고리즘에서 요구하는 행렬 형태로 정렬

8.2 유니버설 함수

np.sum(arr),  arr.sum()
np.mean(arr), arr.mean()
  • 두 가지 호출 방식 — 함수형(np.sum(arr))과 메서드형(arr.sum()) 모두 지원

요약

개념  핵심
ndarray numpy의 핵심 자료구조. 동일 타입의 n차원 배열
array() / asarray() 원본 데이터로부터 배열 생성. asarray는 깊은 카피
arange() / reshape() 연속 수 생성 + 차원 조정. -1로 자동 계산 가능
zeros/ones/empty shape만 부여하고 값 채운 배열. 버퍼 용도
random.randn 정규분포 난수. DL 파라미터 초기화에 활용
브로드캐스팅 shape이 다른 배열 연산 시 차원 자동 확장
dtype / astype 메모리 효율과 형변환 시 정보 손실 고려
슬라이싱 차원 유지. 일괄 변경 패턴에 적합
불리언 인덱싱 조건 기반 필터링. 가장 빈번한 추출 패턴
팬시 인덱싱 위치 직접 지정. pandas iloc의 원형

numpy는 ndarray 중심의 수치 계산 라이브러리로, 차원/타입/인덱싱 개념을 기반으로 pandas·polars·spark 등 상위 도구로 확장되는 데이터 분석의 근간.