14주차 · 통합 코드 워크스루
- W2–W13에서 배운 개념이 하나의 파이프라인 안에서 어떻게 연결되는지 읽는다
- NumPy로 만든 센서 시뮬레이션 데이터가 통계 처리로 이어지는 흐름을 추적한다
- 함수와 NumPy mask가 불량 데이터를 걸러내는 위치를 확인한다
- f-string 테이블과 요약 리포트가 어떤 값을 보여 주는지 해석한다
- 그래프 설계안(
plot_spec)의 제목·축·단위·데이터 길이를 점검한다 - 파이프라인 각 단계에서
assert가 무엇을 보호하는지 설명한다
워크스루 개요: 센서 데이터 분석 파이프라인
Section titled “워크스루 개요: 센서 데이터 분석 파이프라인”시나리오: 건물 내부 온도 센서 1개가 1분 간격으로 24회 측정 데이터를 기록했습니다. 일부 시점에는 불량 데이터(음수값, 극단값)가 섞일 수 있습니다. 이 단일 시계열 데이터를 정제하고, 통계를 계산하고, 요약 리포트를 출력한 뒤 시각화 설계안을 작성합니다.
파이프라인 5단계:
| 단계 | 작업 | 핵심 개념 |
|---|---|---|
| Step 1 | 데이터 생성 | NumPy 배열, np.random 패턴 (W12 복습) |
| Step 2 | 처리 함수 | 필터링, 통계, 분류 함수 (W5, W9, W11) |
| Step 3 | 검증 | 범위 조건, NumPy mask, shape 점검 (W10–W11) |
| Step 4 | 출력 | f-string 테이블, 요약 리포트 (W5) |
| Step 5 | 시각화 설계안 | plot_spec 딕셔너리 (W12) |
Step 1 · 데이터 생성
Section titled “Step 1 · 데이터 생성”12주차 시각화 예제에서 사용한 np.random.default_rng 패턴으로 재현 가능한 센서 데이터를 시뮬레이션합니다.
실제 센서처럼 기저 신호에 노이즈를 추가하고, 의도적으로 불량값(음수, 극단값)을 심어둡니다.
np.arange(n)은 0, 1, 2, ..., n-1 형태의 측정 인덱스를 만듭니다.
# 참고: 데이터 생성 패턴import numpy as np
rng = np.random.default_rng(42) # 재현 가능한 난수 생성기n = 24 # 측정 횟수raw_time = np.arange(n) # 원래 측정 인덱스 (0~23)base_temp = 22.0 # 기저 온도 (°C)temp = base_temp + rng.normal(scale=1.5, size=n) # 노이즈 추가불량 데이터 주입: 실제 센서 오류를 모사하려면 몇 개의 값을 의도적으로 음수나 극단값으로 바꿉니다.
temp[3] = -5.0 # 오류 데이터 (음수)temp[17] = 80.0 # 오류 데이터 (극단값)Step 2 · 처리 함수
Section titled “Step 2 · 처리 함수”데이터를 처리하는 함수를 각 역할에 맞게 분리합니다. 함수를 나누면 테스트하기 쉽고 재사용이 가능합니다.
# 참고: 처리 함수 패턴import numpy as np
def make_valid_mask(data, low, high): """유효 범위 [low, high] 안이면 True, 아니면 False인 mask를 만듭니다.""" return (data >= low) & (data <= high)
def filter_valid(data, valid_mask): """valid_mask가 True인 위치의 값만 남깁니다.""" return data[valid_mask]
def compute_stats(data): """mean, std, min, max 를 딕셔너리로 반환합니다.""" assert len(data) > 0, "통계를 계산할 정상 데이터가 없습니다" return { "mean": round(float(data.mean()), 2), "std": round(float(data.std()), 2), "min": round(float(data.min()), 2), "max": round(float(data.max()), 2), }
def classify_temp(temp_c): """온도를 3단계로 분류합니다.""" if temp_c < 18: return "cold" elif temp_c <= 26: return "normal" else: return "hot"Step 3 · 검증
Section titled “Step 3 · 검증”불량 데이터를 거를 때는 먼저 정상 범위를 조건으로 정하고, NumPy mask로 정상 데이터만 남깁니다. 이 워크스루에서는 정제 후 데이터가 비어 있는지 명시적으로 확인하고, 비어 있으면 평균 대신 None을 반환합니다.
boolean mask는 [True, False, True, ...]처럼 각 위치를 남길지 버릴지 표시하는 배열입니다.
같은 mask를 온도 배열과 시간 인덱스 배열에 함께 적용하면, 불량값을 제거한 뒤에도 원래 측정 번호를 보존할 수 있습니다.
# 참고: 검증 패턴def checked_mean(data): """데이터가 비어 있으면 None을 반환합니다.""" if len(data) == 0: print("경고: 정상 범위 데이터가 없습니다") return None return float(data.mean())Step 4 · 출력
Section titled “Step 4 · 출력”f-string으로 정렬된 테이블과 요약 리포트를 만듭니다. W5에서 배운 포맷 지정자와 정렬 출력을 다시 활용합니다.
# 참고: 출력 패턴stats = {"mean": 22.3, "std": 1.4, "min": 19.8, "max": 24.7}
print(f"{'항목':<8} {'값':>8}")print("-" * 18)for key, val in stats.items(): print(f"{key:<8} {val:>8.2f}")출력 예시:
항목 값------------------mean 22.30std 1.40min 19.80max 24.70Step 5 · 시각화 설계안
Section titled “Step 5 · 시각화 설계안”W12에서 배운 plot_spec 딕셔너리로 시각화 명세를 확인합니다. 실제 그래프 렌더링은 로컬 Python에서 수행하고, 브라우저에서는 설계안 작성과 self-check를 연습합니다.
NumPy 배열은 그대로 출력·계산하기 좋지만, plot_spec처럼 나중에 JSON 형태로 옮길 수 있는 설계안에는 보통 Python 리스트가 더 다루기 쉽습니다.
그래서 clean_time.tolist()처럼 tolist()를 사용해 NumPy 배열을 일반 리스트로 바꿉니다.
# 참고: 시각화 설계안 패턴import numpy as np
clean_time = np.array([0, 1, 2, 4, 5]) # 불량값 제거 후에도 원래 측정 인덱스를 보존clean_temp = np.array([22.1, 22.3, 22.0, 22.4, 22.2])
plot_spec = { "title": "Sensor Temperature over 24 Readings", "x_label": "Measurement Index (-)", "y_label": "Temperature (°C)", "chart_type": "line+markers", "x": clean_time.tolist(), "y": clean_temp.tolist(),}
# self-checkprint("labels_ready:", all([plot_spec["title"], plot_spec["x_label"], plot_spec["y_label"]]))print("same_length:", len(plot_spec["x"]) == len(plot_spec["y"]))파이프라인 출력 예시
Section titled “파이프라인 출력 예시”5단계 흐름을 따라가면, 센서 데이터 분석 결과가 어떤 그래프 구조로 표현되는지 확인할 수 있습니다.
차트를 불러오는 중...
안내 예제 · 전체 파이프라인 미리보기
Section titled “안내 예제 · 전체 파이프라인 미리보기” 코드 흐름 따라 읽기 · 단계별 빈칸 워크스루
Section titled “코드 흐름 따라 읽기 · 단계별 빈칸 워크스루”목표: 파이프라인 Step 1에서 센서 데이터가 만들어지는 흐름을 확인합니다.
읽을 흐름: 24개 온도 데이터가 만들어지고, 음수와 극단값 오류가 각각 1개씩 들어갑니다.
확인할 출력: shape, dtype, 처음 6개 값, 불량값 위치입니다.
목표: 파이프라인 Step 2에서 처리 함수가 역할별로 나뉘는 이유를 확인합니다.
읽을 흐름: 필터링, 통계 계산, 온도 분류 함수가 정제 데이터에 차례대로 적용됩니다.
확인할 출력: 정제 전/후 개수, 통계 딕셔너리, 분류 샘플입니다.
목표: 파이프라인 Step 3에서 빈 데이터 검증 정책을 확인합니다.
읽을 흐름: checked_mean은 정상 배열에서는 평균을 반환하고, 빈 배열에서는 None을 반환합니다.
확인할 출력: 정상 케이스 평균, 빈 배열 결과, assert 통과 여부입니다.
목표: 파이프라인 Step 4에서 통계와 분류 결과가 리포트 형태로 바뀌는 흐름을 확인합니다.
읽을 흐름: f-string 테이블을 만들고, 온도 분류 결과를 카운팅한 뒤 가장 많은 분류를 해석합니다.
확인할 출력: 통계 테이블, 분류별 개수, 해석 문장입니다.
목표: Step 1~5가 하나로 연결될 때 코드가 어떻게 길어지는지 확인합니다.
읽을 흐름: 데이터 생성 → 처리 함수 → 검증 → 출력 → 시각화 설계안 순서로 데이터가 이동합니다.
확인할 출력: 통계 테이블, 분류 카운트, plot_spec self-check, 3문장 해석, assert 실행 여부입니다.
누적 복습 체크리스트
Section titled “누적 복습 체크리스트”이 워크스루에서 한 번에 등장한 개념을 확인해 보세요.
| 주차 | 핵심 개념 | 이 워크스루에서 쓴 곳 |
|---|---|---|
| W2 | 변수·단위 | base_temp = 22.0 (°C), low = 0.0, high = 50.0 |
| W4 | 반복문 | for v in clean_temp: |
| W5 | 함수 | filter_valid, compute_stats, classify_temp |
| W6 | 자료구조 | stats dict, label_counts dict |
| W9 | 리팩토링 | 함수 분해, assert 검증 |
| W10 | 행렬·벡터 기초 | 데이터 표의 행/열, shape 해석 |
| W11 | NumPy | np.array, 불리언 mask, shape 검증 |
| W12 | 시각화 | rng.normal 노이즈 생성, plot_spec 딕셔너리, self-check |
| W13 | 알고리즘 | label_counts 카운팅, classify_temp 분류 |
흐름을 따라간 뒤 확인할 출력
Section titled “흐름을 따라간 뒤 확인할 출력”전체 예시 코드를 실행했을 때 아래 항목이 보이면 흐름을 제대로 따라간 것입니다.
정제 후: 24개 → 22개요약 통계: mean/std/min/max 표분류 카운트: {'cold': ..., 'normal': ..., 'hot': ...}labels_ready: Truesame_length: True전체 파이프라인 흐름 확인