13주차 · 실용 알고리즘과 데이터 활용
13장. 실용 알고리즘과 데이터 활용
Section titled “13장. 실용 알고리즘과 데이터 활용”- 카운팅·정렬·탐색 3가지 패턴을 EE 맥락(센서 로그, 측정값, 임계값)에서 사용한다
dict로 빈도를 세는 카운팅 패턴을 작성한다sorted(..., key=함수)로 측정 레코드를 원하는 기준으로 정렬한다for루프와break로 조건을 만족하는 첫 번째 항목을 효율적으로 탐색한다- 알고리즘 결과를 의사결정 문장으로 요약한다
O(n)과O(n²)차이를 루프 횟수로 직관적으로 설명한다
알고리즘 quickstart: 3가지 패턴 뼈대
Section titled “알고리즘 quickstart: 3가지 패턴 뼈대”초급 단계에서 마주치는 대부분의 문제는 아래 3가지 패턴으로 해결할 수 있습니다.
패턴 1 — 카운팅 (dict)
Section titled “패턴 1 — 카운팅 (dict)”counts = {}for x in items: counts[x] = counts.get(x, 0) + 1패턴 2 — 정렬 (sorted + key 함수)
Section titled “패턴 2 — 정렬 (sorted + key 함수)”def sort_key(item): return item["value"] # 정렬 기준을 함수로 명시한다
ordered = sorted(items, key=sort_key)패턴 3 — 탐색 (in / break)
Section titled “패턴 3 — 탐색 (in / break)”found = Nonefor x in items: if x > threshold: found = x break # 첫 번째 매치에서 즉시 종료처음 쓸 때 체크할 4가지
Section titled “처음 쓸 때 체크할 4가지”- 문제를 먼저 카운팅 / 정렬 / 탐색 중 하나로 분류한다
- 카운팅·조회가 많으면
dict를 쓴다 - 첫 번째 항목만 필요하면
break로 조기 종료한다 - 결과를 의사결정 문장 한 줄로 요약한다
자료구조 선택 기준
Section titled “자료구조 선택 기준”| 자료구조 | 언제 쓰나 | EE 예시 |
|---|---|---|
list | 순서가 중요하고 인덱스로 접근할 때 | 시간별 측정값 시퀀스 |
dict | ”키 → 값” 조회나 카운팅이 많을 때 | 상태 코드별 발생 횟수 |
set | 중복 제거나 포함 여부 검사가 필요할 때 | 고유 채널 번호 집합 |
시간복잡도 직관 (초급용)
Section titled “시간복잡도 직관 (초급용)”O(n): 루프 한 겹 → 데이터 2배면 처리량도 약 2배O(n²): 루프 두 겹 → 데이터 2배면 처리량은 약 4배
1) 카운팅 패턴 — 센서 상태 로그 집계
Section titled “1) 카운팅 패턴 — 센서 상태 로그 집계”센서 로그에서 각 상태(OK / WARN / ERROR)가 몇 번 나왔는지 세면 시스템 상태를 빠르게 파악할 수 있습니다.
counts.get(x, 0) + 1은 처음 보는 키면 0으로 시작하고, 이미 있으면 1 증가시킵니다.
counts.get(status, 0): 딕셔너리에 키가 없으면 0을 기본값으로 반환합니다max(counts, key=get_count):counts딕셔너리의 키 중에서get_count를 적용했을 때 가장 큰 값을 찾습니다- 결과는 단순한 숫자가 아니라 의사결정 문장으로 마무리합니다
2) 정렬 패턴 — 측정값 우선순위 정렬
Section titled “2) 정렬 패턴 — 측정값 우선순위 정렬”정렬은 “어떤 기준으로 우선순위를 매길 것인가”를 코드로 표현하는 과정입니다.
sorted(..., key=함수)에서 key에는 함수 객체를 넘깁니다. lambda도 사용할 수 있지만, 이 수업에서는 가독성을 위해 **이름 있는 함수(def)**를 먼저 권장합니다.
key 파라미터란?
Section titled “key 파라미터란?”sorted(items, key=f)는 각 원소에 함수 f를 적용한 결과를 기준으로 정렬합니다.
함수 이름만 넘기고 괄호는 붙이지 않습니다.
def sort_key(record): return record["snr"] # 함수를 정의하고
ordered = sorted(records, key=sort_key) # 이름만 넘긴다 (sort_key() 가 아님) -ch["snr"]를 쓰는 이유:sorted는 기본 오름차순이므로 내림차순으로 정렬하려면 부호를 반전합니다CH3와CH4는 SNR이 같으므로 두 번째 기준인 채널 ID 오름차순으로 결정됩니다- 정렬 결과의 첫 번째 원소가 최우선 채널입니다
3) 탐색 패턴 — 임계값 초과 항목 찾기
Section titled “3) 탐색 패턴 — 임계값 초과 항목 찾기”탐색은 “조건을 만족하는 항목을 찾는” 패턴입니다.
첫 번째 매치만 필요하면 break로 루프를 즉시 종료해 불필요한 반복을 줄입니다.
break는 첫 번째 매치를 찾은 즉시 루프를 종료합니다 — 이후 데이터를 불필요하게 확인하지 않습니다loop_count를 출력하면 조기 종료 효과를 직접 확인할 수 있습니다first_over is not None조건으로 탐색 실패 케이스를 안전하게 처리합니다
자주 하는 실수
Section titled “자주 하는 실수”| 실수 | 증상 | 수정 방법 |
|---|---|---|
list로 모든 것을 처리 | 같은 키를 반복 탐색해 코드가 길어짐 | 카운팅·조회는 dict로 분리 |
복잡한 lambda 사용 | 정렬 기준이 한 줄에 숨어 읽기 어려움 | def sort_key(x): return ... 형태로 분리 |
break 없는 탐색 | 첫 매치 후에도 루프가 계속 돔 | 첫 매치 직후 break 추가 |
| 해석 문장 없음 | 숫자만 출력하고 끝남 | 의사결정 문장 한 줄 작성 |
| 이중 루프 남용 | 데이터가 커지면 급격히 느려짐 | dict/set 기반 단일 순회로 재설계 |
교정 워크플로 (이론 → 코드 → 해석)
Section titled “교정 워크플로 (이론 → 코드 → 해석)”- 이론: 문제를 “카운팅 / 정렬 / 탐색” 중 하나로 분류한다.
- 이론: 자료구조를 선택하고 루프 겹 수를 예상한다.
- 코드: 가장 짧은 정답 루프부터 작성한다.
- 코드: 중간 결과(
counts,ordered)를 출력해 검증한다. - 해석: 결과를 근거로 다음 행동 문장을 한 줄 작성한다.
실습 문제 · 직접 코딩
Section titled “실습 문제 · 직접 코딩”[기초] 출력 예측: 아래 코드를 실행하기 전에 출력 결과를 예측하고, 실행해서 확인하세요.
[기초] 버그 찾기: 아래 정렬 코드에는 버그가 1개 있습니다. 찾아서 고치세요.
[응용] 센서 로그 카운팅: 센서 상태 로그에서 각 상태의 빈도를 세고 가장 많은 상태를 출력하세요.
[응용] 임계값 탐색: 전압 측정 시계열에서 임계값을 처음 초과하는 시점을 찾으세요.
[도전] 카운팅 + 정렬 + 탐색 통합: 채널 측정 로그에서 상태별 빈도를 세고, 수신 전력 기준으로 정렬하고, 임계값을 초과하는 첫 번째 채널을 찾으세요.