728x90
데이터 분석에서 수치 연산이 제대로 되려면, 비정상 값(NaN, inf) 을 먼저 잡아야 합니다.
이 값들은 다음과 같은 문제를 일으킵니다.
- np.mean, np.sum, np.min 등 모든 통계함수를 무력화
- Pandas/NumPy/Sklearn이 이상하게 작동함
- 조건 필터링이 안 됨, 모델 입력이 망가짐
항목 | NaN | inf / -inf |
의미 | Not a Number | 무한대 (±∞) |
발생 원인 | 0/0, sqrt(-1), log(-x) | 1/0, overflow |
비교 | NaN != NaN (항상 False) | inf == inf, -inf == -inf |
감지 방법 | np.isnan() | np.isinf() |
NaN과 inf를 감지하는 함수
Numpy에서 NaN과 inf를 감지하는 함수들이 있습니다.
바로 np.isnan(x), np.isinf(x), np.isfinite(x) 입니다.
함수 | 감지 대상 | 반환 | 메모리 복사 여부 | axis 지원 | 주요 사용처 |
np.isnan(x) | NaN만 | bool 배열 | 복사 | ❌ | 결측값 탐지 |
np.isinf(x) | ±inf | bool 배열 | 복사 | ❌ | 무한값 감지 |
np.isfinite(x) | NaN + inf 제외 | bool 배열 | 복사 | ❌ | 정상 수치만 필터링 |
x = np.array([1, np.nan, np.inf, -np.inf, 5])
np.isnan(x) # [False True False False False]
np.isinf(x) # [False False True True False]
np.isfinite(x) # [True False False False True]
위 함수들은 모두 원본에는 영향을 주지 않으며, 반환 결과는 새로운 boolean배열 입니다.
→ Boolean indexing에 바로 사용 가능합니다.
그럼 NaN이 있는 상태에서 연산 가능한 함수도 보겠습니다.
함수 | 동작 방식 | NaN 무시 | axis 지원 | 복사 발생 여부 |
np.nanmean(x) | NaN 제외 후 평균 | 🟢 | 🟢 | 복사됨 |
np.nanpercentile(x, q) | NaN 제외 후 백분위 계산 | 🟢 | 🟢 | 복사됨 |
x = np.array([1, 2, np.nan, 4])
np.nanmean(x) # → 2.333...
np.nanpercentile(x, 50) # → 2.333...
axis 사용 시 처리 방식
import numpy as np
m = np.array([[1, 2, np.nan],
[4, np.nan, 6]])
np.nanmean(m, axis=0) # 열 평균 → [2.5, 2, 6]
np.nanmean(m, axis=1) # 행 평균 → [1.5, 5]
- axis=0 → 열 기준 연산
- axis=1 → 행 기준 연산
- NaN을 제외하고 나머지 값만 계산됨
- 결과는 별도 배열로 반환되며 원본은 변하지 않음
1. NaN을 제거한 후 평균 구하기
data = np.array([10, 20, np.nan, 30])
clean_mean = np.nanmean(data)
2. inf 또는 NaN이 있는 값 제거
x = np.array([1, 2, np.nan, np.inf, 5])
x_clean = x[np.isfinite(x)] # → [1, 2, 5]
3. log 연산 후 정상 값만 추출
x = np.array([1, 0, -1])
log_x = np.log(x) # → [0. nan nan]
log_x[np.isfinite(log_x)] # → [0.]
주의점
실수 | 설명 | 해결 방법 |
x == np.nan | 항상 False → NaN은 자기 자신과도 같지 않음 | np.isnan(x) 사용 |
np.mean(x)에 NaN 있음 | 결과 전체가 NaN | np.nanmean(x)로 대체 |
np.percentile(x)에 NaN 있음 | percentile 전체가 NaN | np.nanpercentile(x) 사용 |
inf 값만 제거하면 된다 착각 | NaN도 있어야 정상 연산 가능 | np.isfinite(x) 사용 |
메모리 처리 관점에서
함수 | 메모리 복사 | inplace 지원 | 원본 영향 |
np.isnan, np.isinf, np.isfinite | 새 배열 반환 (copy) | ❌ | ❌ |
np.nanmean, np.nanpercentile | 복사된 배열 연산 | 🟢 (연산 결과만) | ❌ |
직접 슬라이싱 (x[~np.isnan(x)]) | 새로운 배열 반환 | ❌ | ❌ |
결론은 모든 연산은 복사 기반이고 원본은 변하지 않습니다.
대용량에서는 memory-efficient logic이 중요합니다.
총 함수별 요약
함수 | 대상 | NaN 무시 | inf 무시 | 반환 | axis지원 | 설명 |
isnan(x) | NaN | ✅ | ❌ | bool | ❌ | NaN만 True |
isinf(x) | inf | ❌ | ✅ | bool | ❌ | ±inf만 True |
isfinite(x) | 정상값 | ✅ | ✅ | bool | ❌ | NaN/inf 제외 |
nanmean(x) | 수치 | ✅ | ❌ | float or array | ✅ | 평균 |
nanpercentile(x, q) | 수치 | ✅ | ❌ | float or array | ✅ | 백분위수 |
Numpy는 결측값과 무한값을 다루기 위해
세분화된 함수와 최적화된 연산 방식을 제공합니다.
결측 / 이상값 분석을 잘 하기 위해서는 반드시 다음 기준을 기억해야 합니다.
- 검사할 땐 isnan, isinf, isfinite
- 연산할 떈 nanmean, nanpercentile
- 정상값만 추출할 땐 x[isfinite(x)]
728x90
반응형
'python > Pandas | Numpy' 카테고리의 다른 글
[Numpy] np.dot (Dot Product) (0) | 2025.05.26 |
---|---|
[Numpy] where, argmax, unique, argsort (0) | 2025.05.16 |
[Numpy] 슬라이싱, 마스킹, 조건 추출 (0) | 2025.05.02 |
[Numpy] 브로드캐스팅(broadcasting)과 벡터화(vectorization) 연산 (0) | 2025.05.02 |
[Numpy] ndarray 구조 - 배열의 모양, 차원 ,타입 (0) | 2025.05.02 |