파이썬 기초부터 데이터 분석, 데이터베이스까지 — 각 과정마다 2주 커리큘럼으로 의료 데이터를 다루는 실력을 키워요.
커리큘럼 보기 →AI 헬스케어를 공부하고 싶은데 어디서부터 시작해야 할지 막막한 분들을 위해 만들었어요.
딱딱한 이론 대신, 실제 의료 데이터 예시와 인터랙티브 가이드로 직접 손을 움직이며 배울 수 있도록 구성했어요.
| 문법 | 이름 | 언제 | 예시 |
|---|---|---|---|
| [ ] | 리스트/인덱싱 | 목록, 값 꺼낼 때 | df["bp"] |
| ( ) | 함수실행/튜플 | 함수 뒤, 수정불가 목록 | print("x") |
| { } | 딕셔너리/집합 | 키:값 저장 | {"name":"김"} |
| . | 점 표기법 | 소속 기능 쓸 때 | df.head() |
| 종류 | 수학적 의미 | 헬스케어 예시 | Python |
|---|---|---|---|
| 스칼라 | 하나의 숫자 | 환자 나이: 45 | age = 45 |
| 벡터 | 1차원 숫자 배열 | 환자 정보: [키, 몸무게, 나이] | np.array([170, 70, 45]) |
| 행렬 | 2차원 숫자 배열 | 여러 환자의 검사수치 모음 | np.array([[...],[...]]) |
| 함수 | 형태 | 특징 | 헬스케어 활용 |
|---|---|---|---|
| 선형 (Linear) | y = wx + b | 직선, 연속값 예측 | 혈당 수치 예측 |
| 지수 (Exponential) | y = eˣ | 폭발적 증가/감소 | 바이러스 전파 모델링 |
| 로그 (Logarithm) | y = log(x) | 큰 값 압축 | 약물 농도, 음압 측정 |
| 시그모이드 (Sigmoid) | y = 1/(1+e⁻ˣ) | 0~1 사이 확률 출력 | 암 진단 확률 출력 |
| 항목 | CSV 파일 | Database |
|---|---|---|
| 데이터 크기 | 작을 때만 가능 | 수백만 행 가능 |
| 구조 | 단일 표 | 여러 표가 연결됨 |
| 검색 속도 | 느리고 비효율 | 인덱스로 매우 빠름 |
| 업데이트 | 어려움 | 안정적 (트랜잭션) |
| 협업 | 파일 공유 | 여러 명이 동시에 사용 |
| 용어 | 의미 | 헬스케어 예시 |
|---|---|---|
| Table | 데이터 저장 단위 | patients, visits |
| Column | 속성 | patient_id, name, bp |
| Row | 데이터 한 건 | 환자 1명의 정보 |
| PK (Primary Key) | 고유 식별자 | patient_id (중복불가) |
| FK (Foreign Key) | 다른 테이블 PK 참조 | visits.patient_id |
| Schema | 테이블 구조 정의서 | 컬럼명, 타입, 제약조건 |
| 타입 | 용도 | 예시 |
|---|---|---|
| INT / BIGINT | 정수 | patient_id, 나이 |
| DECIMAL(p,s) | 정밀한 실수 | BMI, 혈당 ← 의료필수! |
| VARCHAR(n) | 가변 문자열 | 이름, 진단명 |
| DATE / DATETIME | 날짜/시간 | visit_date |
| BOOLEAN | 참/거짓 | is_diabetic |
| 위치 | 역할 | 특징 | 예시 |
|---|---|---|---|
| SELECT 뒤 AS | 결과표의 이름표 | 여러 번 자유롭게 사용 가능 | name AS '환자이름' |
| FROM/JOIN 뒤 AS | 테이블의 신분 교체 | 한번 바꾸면 끝까지 그 이름만 사용! | patients AS p |
| 상황 | DISTINCT 활용 예 |
|---|---|
| 진료 과목 종류 확인 | SELECT DISTINCT specialty FROM doctors |
| 방문한 적 있는 환자 목록 | SELECT DISTINCT patient_id FROM admissions |
| 거주 지역 종류 | SELECT DISTINCT city FROM patients |
| 단계 | 이름 | 핵심 규칙 | 비유 |
|---|---|---|---|
| 1NF | 제1정규화 | 한 셀에 하나의 값만 | 칸마다 옷 하나씩만 |
| 2NF | 제2정규화 | 부분 함수 종속 제거 | 세트 상품은 세트 전체 정보만 |
| 3NF | 제3정규화 | 이행적 종속 제거 | 내 친구의 친구는 별도 소개 |
| BCNF | 보이스-코드 정규형 | 모든 결정자가 후보키 | 3NF의 강화 버전 |
| 구분 | 정규화 | 역정규화 |
|---|---|---|
| 목적 | 데이터 무결성, 중복 제거 | 읽기 성능 최적화 |
| 테이블 수 | 많음 (분리) | 적음 (통합) |
| JOIN | 많이 필요 | 적게 필요 |
| 쓰기 속도 | 빠름 (한 곳만 수정) | 느림 (여러 곳 수정) |
| 읽기 속도 | 상대적으로 느림 | 빠름 |
| 헬스케어 적용 | EMR 마스터 데이터 | 분석용 리포트, 대시보드 |
| 이상 현상 | 설명 | 예시 (비정규화 상태) |
|---|---|---|
| 삽입 이상 | 불필요한 데이터를 같이 넣어야 하는 상황 | 환자 없이 진료과를 등록 못 함 |
| 삭제 이상 | 삭제 시 의도치 않은 데이터도 사라짐 | 마지막 환자 삭제 시 진료과 정보도 사라짐 |
| 갱신 이상 | 일부만 수정돼 데이터 불일치 발생 | 전화번호 변경 시 일부 환자 행만 수정 |
| 지표 | 의미 | 수식 | 헬스케어 예시 |
|---|---|---|---|
| 평균 (mean) | 전체 합 ÷ 개수 | Σx / n | 평균 혈압 128.5 mmHg |
| 중앙값 (median) | 정렬 후 가운데 값 | 순서[n/2] | 이상치에 강해 의료에서 선호 |
| 표준편차 (std) | 값들의 퍼짐 정도 | √분산 | 혈압 측정값의 변동성 |
| IQR | 중간 50% 범위 | Q3 - Q1 | 이상치 탐지에 사용 |
| 상관계수 | 두 변수 관계 -1~1 | r | 나이와 혈압의 관계 |
| 지표 | 의미 | 예시 |
|---|---|---|
| 왜도(Skewness) | 비대칭 정도 | 입원기간: 우측 꼬리 |
| 첨도(Kurtosis) | 뾰족한 정도 | 희귀질환 발생률 |
| 단계 | 내용 | 예시 |
|---|---|---|
| 귀무가설 H₀ | 차이 없음(기본 가정) | 약이 혈압에 영향 없음 |
| 대립가설 H₁ | 차이 있음(증명 목표) | 약이 혈압을 낮춤 |
| p-value 계산 | 우연히 이런 결과 확률 | p = 0.023 |
| 결론 | p < 0.05 → H₁ 채택 | 약이 효과 있음! |
| 구분 | 예측: 양성 (Positive) | 예측: 음성 (Negative) |
|---|---|---|
| 실제: 양성 | TP — True Positive 암 환자를 암으로 정확히 탐지 | FN — False Negative 암 환자를 정상으로 놓침 (매우 위험!) |
| 실제: 음성 | FP — False Positive 정상인을 암으로 오진 | TN — True Negative 정상인을 정상으로 정확히 판단 |
| 지표 | 공식 | 중점 | 헬스케어 예시 |
|---|---|---|---|
| 정확도 (Accuracy) | (TP+TN) / 전체 | 전체 정답률 | 편향된 데이터에 취약 |
| 민감도 (Recall) | TP / (TP+FN) | 놓치지 않기 | 암 진단 AI의 핵심 지표 |
| 특이도 (Specificity) | TN / (TN+FP) | 오진 줄이기 | 정상인 과잉 검사 방지 |
| 정밀도 (Precision) | TP / (TP+FP) | 양성 예측 신뢰도 | 불필요한 추가 검사 최소화 |
| F1 Score | 2 × P×R / (P+R) | 민감도+정밀도 조화 | 불균형 데이터에 적합 |
| AUC-ROC | ROC 곡선 아래 면적 | 임계값 무관 성능 | AI 모델 종합 성능 평가 |
| 방법 | 특징 | 추천 상황 |
|---|---|---|
| f-string | 코드 안에 변수 직접 삽입. 간결하고 빠름 | 일반적인 출력, 로컬 변수 사용 시 |
| Template | $변수명 방식. 외부 데이터로 채울 때 안전 | 외부 입력·딕셔너리 데이터 활용 시 |
| safe_substitute() | 변수 없어도 에러 없이 그냥 $변수명으로 표시 | 일부 변수가 없을 수 있는 경우 |
| 부분 | 의미 |
|---|---|
| [ ... ] | 결과가 새 리스트에 담겨요 |
| t (앞) | 결과(Expression): 리스트에 넣을 값 |
| for t in temperatures | 반복(Iteration): 순서대로 꺼내기 |
| if t >= 37.5 | 필터(Filter): 조건 맞을 때만 포함 |
| 비교 항목 | for 반복문 | while 반복문 |
|---|---|---|
| 반복 기준 | 횟수(Range)나 리스트가 정해짐 | 조건(Condition)이 참인 동안 |
| 반복 횟수 | 미리 알고 있음 | 모를 수도 있음 |
| 안전성 | 리스트가 끝나면 자동 종료 | 조건이 False가 안 되면 무한루프 |
| 주요 사용 | 환자 목록 순회, 고정된 반복 | 조건 기반 모니터링, 약물 투여 |
| SQL 구문 | SQLAlchemy Core | 설명 |
|---|---|---|
| CREATE TABLE | Table(...), metadata.create_all() | 테이블 구조 정의 및 생성 |
| SELECT * FROM t | select(table) | 테이블 전체 조회 |
| WHERE 조건 | .where(...) | 조건 필터링 |
| ORDER BY col | .order_by(col.desc()) | 정렬 |
| LIMIT n | .limit(n) | 결과 개수 제한 |
| COUNT / AVG | func.count() / func.avg() | 집계 함수 |
| AS 별칭 | .label('별칭') | 컬럼 별명 지정 |
| GROUP BY | .group_by(...) | 그룹화 |
| HAVING 조건 | .having(...) | 그룹 필터링 |
| INNER / LEFT JOIN | .join(t, 조건) / isouter=True | 테이블 연결 |
| INSERT INTO | table.insert(), conn.execute() | 데이터 추가 |
| UPDATE SET | update(t).where().values() | 데이터 수정 |
| DELETE FROM | delete(t).where() | 데이터 삭제 |
| 방법 | 장단점 |
|---|---|
| PyMySQL / sqlite3 | Raw SQL 직접 작성 — 오타 찾기 어렵고 가독성 떨어짐 |
| pandas read_sql | 조회는 쉽지만 복잡한 수정/삭제에서 한계 |
| SQLAlchemy Core | Python 메서드 방식 — 가독성↑, 보안↑, 유지보수 쉬움 |
| 방법 | 용도 | 예시 |
|---|---|---|
| result.fetchall() | 모든 행을 리스트로 반환 | 소규모 데이터 확인 |
| result.fetchone() | 결과 1행만 반환 (메모리 절약) | 존재 여부 확인, ID 조회 |
| pd.DataFrame(result) | 결과를 DataFrame으로 변환 | 분석·시각화할 때 |
| 상황 | 인덱스 없을 때 | 복합 인덱스 있을 때 |
|---|---|---|
| ORDER BY 정렬 | 데이터를 가져온 후 별도 정렬(filesort 발생) | 이미 정렬된 순서대로 읽기만 함 |
| GROUP BY 그룹화 | 전체 데이터를 불러와 집계 | 정렬된 데이터를 순서대로 카운트 |
| JOIN 연결 | 매번 테이블 전체를 스캔 | 연결 컬럼으로 바로 찾기 |
| EXPLAIN 항목 | 좋은 상태 | 나쁜 상태 |
|---|---|---|
| type | const / ref / range → 인덱스 활용 | ALL → Full Table Scan (위험!) |
| key | 인덱스 이름이 표시됨 | NULL → 인덱스 미사용 |
| rows | 숫자가 작을수록 좋음 | 전체 행 수와 같으면 비효율 |
| Extra | Using index (커버링 인덱스 — 최적!) | Using filesort (별도 정렬 발생) |
| 항목 | 설명 | 헬스케어 예시 |
|---|---|---|
| 읽기(SELECT) 향상 | WHERE, JOIN, ORDER BY 속도 향상 | 환자 조회, 혈압 범위 검색 |
| 쓰기(CUD) 저하 | INSERT/UPDATE/DELETE 시 인덱스도 재정렬 | 실시간 측정값 삽입 시 느려짐 |
| 페이지 분할 | 인덱스 페이지 가득 차면 고비용 분할 발생 | 대량 데이터 삽입 시 성능 급락 |
| 저장 공간 | 테이블 크기의 약 10% 추가 점유 | 대형 EMR DB에서 무시 못할 용량 |
| 유형 | 특징 |
|---|---|
| Range Scan | 특정 범위 조회. 가장 일반적이고 효율적 |
| Full Index Scan | 인덱스 전체를 읽음. 테이블 Full Scan보단 낫지만 비효율 |
| Skip Scan | 복합 인덱스에서 첫 컬럼 조건 없어도 건너뛰며 검색 (MySQL 8.0+) |
| Covering Index | SELECT 컬럼이 모두 인덱스에 있어 Data Page 방문 0회 — 최적! |
| RDBMS의 한계 | 상황 | NoSQL 해결책 |
|---|---|---|
| 스키마 변경 어려움 | 의료기기 센서 항목이 자주 바뀜 | 스키마 자유 — 컬럼 추가 없이 필드 추가 |
| JOIN 성능 저하 | 환자·검사·처방을 한번에 조회 | 중첩 Document로 하나에 저장 |
| 비정형 데이터 저장 어려움 | IoT 웨어러블 센서 로그 | JSON 형태로 자유롭게 저장 |
| 초당 수만건 기록 부적합 | 실시간 심박수·혈압 모니터링 | Scale-out(수평 확장) 가능 |
| 종류 | 대표 DB | 특징 |
|---|---|---|
| Document DB | MongoDB | JSON 형태. 헬스케어 로그에 자주 사용 |
| Key-Value Store | Redis, DynamoDB | 세션·캐시·실시간 순위 |
| Wide-column DB | Cassandra | 대규모 시계열 데이터 |
| Graph DB | Neo4j | 관계 중심 데이터 (약물 상호작용) |
| 상황 | 추천 DB |
|---|---|
| EMR 환자 정보, 처방 기록 (정형 관계) | MySQL / PostgreSQL |
| IoT 센서 로그, 웨어러블 데이터 | MongoDB |
| 검사 항목이 환자마다 달라지는 경우 | MongoDB |
| 금융·청구 데이터 (무결성 필수) | RDBMS (트랜잭션) |
| RDBMS | MongoDB | 설명 |
|---|---|---|
| Database | Database | 데이터 묶음 단위 |
| Table (테이블) | Collection (컬렉션) | 데이터 저장 공간 |
| Row (행) | Document (문서) | 데이터 한 건 |
| Column (열) | Field (필드) | 데이터 속성 |
| JSON | BSON (Binary JSON) |
|---|---|
| 텍스트 기반 — 가볍고 읽기 쉬움 | 바이너리 기반 — 저장·전송 빠름 |
| 날짜, 이진 데이터 표현 어려움 | 날짜, ObjectId, 이진 데이터 지원 |
| 우리가 코드에서 dict로 작성 | MongoDB가 내부적으로 BSON 사용 |
| RDBMS 정규화 | MongoDB 역정규화 |
|---|---|
| 중복 제거, 테이블 분리 | 중복 허용, 하나의 Document로 통합 |
| JOIN으로 데이터 연결 | 중첩 Document로 JOIN 불필요 |
| 쓰기 성능 최적화 | 읽기 성능 최적화 |
| 연산자 | 의미 | 예시 | SQL 대응 |
|---|---|---|---|
| $eq | 같다 | {"sex": {"$eq": "M"}} | WHERE sex = 'M' |
| $ne | 같지 않다 | {"status": {"$ne": "inactive"}} | WHERE status != 'inactive' |
| $gt | 크다 | {"age": {"$gt": 60}} | WHERE age > 60 |
| $gte | 크거나 같다 | {"sys": {"$gte": 140}} | WHERE sys >= 140 |
| $lt | 작다 | {"hdl": {"$lt": 40}} | WHERE hdl < 40 |
| $lte | 작거나 같다 | {"bmi": {"$lte": 25}} | WHERE bmi <= 25 |
| $in | 목록 중 하나 | {"diagnosis": {"$in": ["당뇨","고혈압"]}} | WHERE diagnosis IN (...) |
| $nin | 목록에 없음 | {"tag": {"$nin": ["deleted"]}} | WHERE tag NOT IN (...) |
| 연산자 | SQL 대응 | 예시 |
|---|---|---|
| $gte / $lte | WHERE col >= n | {"sys": {"$gte": 140}} |
| $gt / $lt | WHERE col > n | {"hdl": {"$lt": 40}} |
| $eq / $ne | WHERE col = / != | {"sex": {"$eq": "M"}} |
| $or / $and | OR / AND | {"$or": [{...},{...}]} |
| $set | SET col = val | update에서 사용 |
| $match | WHERE | aggregate 파이프라인 |
| $group | GROUP BY | {"_id": "$sex"} |
| $sort | ORDER BY | {"risk": -1} (내림차순) |
| $project | SELECT 컬럼 지정 | {"name": 1, "_id": 0} |
| $addFields | 새 컬럼 계산 | {"$add": ["$ldl","$sys"]} |
find()는 커서(cursor) 객체를 반환해요. 리스트가 아니라 데이터를 한 건씩 꺼내는 포인터예요. 대용량 데이터에서 메모리를 절약하는 방식이에요.| 인덱스 유형 | 생성 방법 | 특징 |
|---|---|---|
| 단일 필드 | create_index("field") | 하나의 필드 기준 검색 속도 향상 |
| 복합 인덱스 | create_index([("f1",1),("f2",-1)]) | 두 필드 조합 쿼리 최적화 |
| 유니크 인덱스 | create_index("f", unique=True) | 중복 값 삽입 방지 |
| 멀티키 인덱스 | 배열 필드에 자동 생성 | 배열 안 요소 검색 속도 향상 |
| 자주 나오는 에러 | 원인 | 발생 상황 |
|---|---|---|
| ZeroDivisionError | 0으로 나누기 | BMI = weight / height²에서 height = 0 |
| ValueError | 잘못된 값 변환 | int("혈압정상") — 문자를 숫자로 변환 |
| KeyError | 없는 딕셔너리 키 | patient["혈당"] — 혈당 필드가 없는 경우 |
| IndexError | 리스트 범위 초과 | records[99] — 기록이 99개 미만인 경우 |
| FileNotFoundError | 파일 없음 | CSV 경로가 틀린 경우 |
| TypeError | 자료형 불일치 | 문자열 + 숫자 연산 |
| 함수 | 설명 | 헬스케어 예시 |
|---|---|---|
| enumerate() | 인덱스 + 값을 함께 순회 | 환자 번호를 붙이며 기록 출력 |
| zip() | 여러 리스트를 묶어서 순회 | 환자명 + 혈압 + 혈당을 묶기 |
| map() | 모든 요소에 함수 적용 | 혈압 목록 → mmHg→kPa 변환 |
| filter() | 조건을 만족하는 요소만 | 고혈압 환자만 추출 |
| sorted() | 정렬 (원본 유지) | 혈당 수치로 오름차순 정렬 |
| any() / all() | 하나라도 True / 모두 True | 위험 지표 중 하나라도 이상 여부 |
| isinstance() | 자료형 확인 | 혈압값이 int인지 확인 |
| round() | 반올림 | BMI 소수점 1자리 |
| 라이브러리 | 용도 | 헬스케어 활용 |
|---|---|---|
| datetime | 날짜·시간 처리 | 환자 나이 계산, 입원 기간 산출 |
| math | 수학 함수 | 로그, 제곱근, 올림/내림 |
| random | 난수 생성 | 테스트 데이터 생성, 무작위 샘플링 |
| os | 파일·경로 관리 | 데이터 파일 경로 처리 |
| json | JSON 읽기·쓰기 | API 응답 파싱, 설정 파일 |
| import 방식 | 예시 | 특징 |
|---|---|---|
| 전체 import | import pandas | pandas.DataFrame()으로 사용 |
| 별칭 import | import pandas as pd | pd.DataFrame()으로 짧게 사용 |
| 특정 항목만 | from datetime import date | date()만 가져옴 |
| 여러 항목 | from math import ceil, floor | 여러 함수를 직접 사용 |
| 메타문자 | 의미 | 예시 |
|---|---|---|
| . | 임의의 문자 1개 | a.c → abc, a1c |
| * | 앞 문자 0번 이상 | ca*t → ct, cat, caat |
| + | 앞 문자 1번 이상 | ca+t → cat, caat |
| ? | 앞 문자 0 또는 1번 | ca?t → ct, cat |
| ^ | 문자열 시작 | ^혈압 → "혈압..."으로 시작 |
| $ | 문자열 끝 | 정상$ → "...정상"으로 끝남 |
| [abc] | a, b, c 중 하나 | [MF] → M 또는 F |
| \d | 숫자 (0~9) | \d+ → 1개 이상의 숫자 |
| \s | 공백 문자 | 탭, 스페이스, 줄바꿈 |
| 구분 | 내용 |
|---|---|
| 데이터 출처 | Kaggle — Forensic Biometric Wearable Dataset |
| 사용 기술 | Python · pandas · MySQL (SQLAlchemy + ipython-sql) · MongoDB (PyMongo) |
| 진행 방식 | 5명 팀 / 필수 1번 + 선택 3문제 이상 |
| 제출물 | Colab 파일 필수, PPT 선택 / 팀당 약 10분 발표 |
| 컬럼 | 의미 | 단위 / 범주 |
|---|---|---|
| timestamp | 측정 시각 | 1분 단위 시계열 |
| heart_rate | 심박수 | bpm (위험: >150) |
| blood_oxygen | 혈중 산소 포화도 (SpO₂) | % (위험: <94) |
| body_temp | 체온 | °C (이상: ≥38.0) |
| resp_rate | 호흡수 | 회/분 |
| step_count | 걸음 수 | count |
| activity | 활동 종류 | Resting / Walking / Running / Cycling |
| accel_x/y/z | 가속도 센서 | m/s² |
| gyro_x/y/z | 각속도 (자이로) | °/s |
| is_tampered | 이상 데이터 여부 | 0=정상, 1=오류(제거 필요) |
| 단계 | 명칭 | 내용 |
|---|---|---|
| 1 | 기준점 설정 | 가공되지 않은 Raw Data 초기 상태 파악 — 오류 포함 상태 확인 |
| 2 | 데이터 정제 | is_tampered == 0 필터링으로 신뢰할 수 있는 Clean Data 추출 |
| 3 | 대조 분석 | 전체 vs 정상 집단의 지표를 각각 산출하여 시각적 대조 |
| 4 | 왜곡도 수치화 | 전체 평균 - 정상 평균 계산으로 센서 오류의 영향력 정량화 |
| 5 | 의료적 통찰 | 수치 차이가 임상 진단에 미치는 영향 해석 (과잉 처방 위험 등) |
| 단계 | 명칭 | 내용 | 웨어러블 예시 |
|---|---|---|---|
| 1 | EDA & 이상치 식별 | Boxplot·Histogram으로 분포 시각화, 이상치 탐지 | 심박수 boxplot → 150 초과 극단값 확인 |
| 2 | 원인 분석 (Root Cause) | 이상치가 기술적 오류인지 실제 생리적 이상인지 구분 | is_tampered=1 vs. 실제 빈맥 구분 |
| 3 | 목적별 데이터 정제 | 분석 목적에 따라 제거/보정/별도분리 결정 | 평균 분석엔 오류 제거, 위험 감지엔 보존 |
| 4 | 대조 분석 | 이상치 포함/제거 전후 수치 비교 및 왜곡도 수치화 | "오류 제거 후 평균 심박수 -5 bpm" |
| 5 | 도메인 전문가 검증 | 임상적으로 가능한 수치인지 의료 전문가 확인 | 의사에게 "체온 42°C가 가능한가?" 확인 |
| 신호 | 판단 근거 |
|---|---|
| is_tampered = 1 | 센서 탈착·네트워크 오류 플래그 |
| 심박수 높음 + 걸음수 = 0 | Resting인데 심박 급상승 → 센서 오작동 가능성 |
| 체온 35°C 미만 또는 42°C 초과 | 생존 불가 수치 → 측정 오류 |
| 산소포화도 80% 미만 | 의식 불명 수준 → 탈착 오류일 가능성 높음 |
| 신호 | 의미 |
|---|---|
| Running 중 심박수 180 | 격렬한 운동 → 정상 생리 반응 |
| 야간 산소포화도 93% | 수면 무호흡증 가능성 → 위험 신호! |
| 안정 중 체온 38.5°C | 발열 → 즉각 알람 대상 |
| 패턴 | 판단 | 조치 |
|---|---|---|
| 심박↑ + 걸음수↑ + Running | 운동 중 정상 생리 반응 | 보존 — 위험군 아님 |
| 심박↑ + 걸음수=0 + Resting | 센서 오류 가능성 매우 높음 | is_tampered 확인 후 제거 |
| 체온↑ + 심박↑ + 호흡↑ | 실제 발열 — 3중 확인 | 보존 + 위험 알람 대상 |
| 산소포화도↓ + 걸음수=0 + 야간 | 수면 무호흡 의심 | 의료 전문가 검토 필요 |
| 분석 항목 | 수행 내용 |
|---|---|
| 고심박·고열 탐지 | 심박수 150 초과 또는 체온 38°C 이상 구간 추출 → 활동별 신체 부하 분석 |
| 복합 위험군 분석 | 고심박+고열·호흡부전(저산소+과호흡)·심폐과부하 다중 조건 집계 |
| 활동별 생체 패턴 | Resting·Running·Walking·Cycling 평균 심박수·호흡수 대조 → 활동 강도 수치화 |
| 시간대별 트렌드 | 24시간 주기 심박·체온 변화 → 생체 리듬 이상 여부 확인 |
| 이상치 영향도 | 센서 오류 포함/제거 전후 지표 비교 → 왜곡 정도 정량화 |
| 기술 | 활용 내용 |
|---|---|
| MySQL + SQLAlchemy | %%sql 매직 + HOUR(), GROUP BY, UNION ALL로 집계 및 시계열 분석 |
| MongoDB Aggregation | $match·$group·$project·$hour 파이프라인으로 서버 측 효율적 처리 |
| pandas DataFrame | 모든 결과를 display()로 시각화, 컬럼명을 한글로 변환해 가독성 향상 |
| 방향 | 내용 |
|---|---|
| 시계열 시각화 | 시간대별 심박·체온 변화를 라인 그래프로 시각화 → 생체 리듬 직관적 파악 |
| 실시간 알람 로직 | 복합 위험 조건 기반 모니터링 시스템 구축 (예: 고심박+저산소 동시 발생 시 알람) |
| 머신러닝 확장 | 위험군 데이터를 학습 데이터로 활용해 이상 탐지(Anomaly Detection) 모델 개발 |
| 단계 | 명칭 | 주요 코드 | 의료적 의미 |
|---|---|---|---|
| 1 | 데이터 파악 | df.shape / df.dtypes / df.describe() | 몇 명 환자? 어떤 지표? 정상 범위인가? |
| 2 | 품질 점검 | df.isnull().sum() / df.duplicated() | 측정 누락, 중복 기록 탐지 |
| 3 | 분포 시각화 | df.hist() / sns.boxplot() | 수치 범위, 이상치, 왜도 확인 |
| 4 | 가설 설정 & 검증 | stats.ttest_ind() / pearsonr() | "Running이 심박수에 영향 주는가?" |
| 5 | 결과 해석 & 보고 | data_quality_report() / 시각화 | 임상적 의미, 한계점 명시 |
| 분석 항목 | 시각화 방법 | 의학적 해석 포인트 |
|---|---|---|
| 생체 지표 분포 | 히스토그램 | 정상 범위(60~100bpm) 비율, 위험 구간 비율 |
| 활동별 차이 | 박스플롯 | 중앙값 차이, 이상치 위치, IQR 너비 |
| 변수 간 관계 | 히트맵 / 산점도 | r>0.5 강한 상관, 임상적 의미 설명 |
| 24시간 패턴 | 라인 차트 | 서카디안 리듬, 수면 시간대 이상 여부 |
| 위험군 분포 | 스택 바 차트 | 활동별 위험 비율, Resting 위험이 핵심 |
| 가설 검증 | p-value 수치 | p<0.05: 유의미, 상관≠인과 항상 명시 |
| 챕터 | 범위 | 분류 | 대표 질환 |
|---|---|---|---|
| I | I00–I99 | 순환계 | I10 고혈압, I21 심근경색, I63 뇌경색 |
| E | E00–E89 | 내분비·대사 | E11 2형 당뇨, E66 비만, E78 고지혈증 |
| C | C00–C96 | 악성 신생물(암) | C34 폐암, C50 유방암, C61 전립선암 |
| J | J00–J99 | 호흡기계 | J18 폐렴, J44 COPD, J45 천식 |
| N | N00–N99 | 비뇨생식계 | N18 만성 신부전, N39 요로감염 |
| F | F00–F99 | 정신·행동 장애 | F32 우울증, F41 불안장애 |
| Z | Z00–Z99 | 건강 관련 요인 | Z00 건강검진, Z23 예방접종 |
| 구분 | 수축기 SBP (mmHg) | 이완기 DBP (mmHg) | 의미 |
|---|---|---|---|
| 정상 | < 120 | < 80 | 건강한 혈압 |
| 주의 (상승) | 120–129 | < 80 | 생활습관 개선 권고 |
| 고혈압 전단계 | 130–139 | 80–89 | 약물 고려 시작 |
| 고혈압 1기 | 140–159 | 90–99 | 약물 치료 시작 |
| 고혈압 2기 | ≥ 160 | ≥ 100 | 즉각 치료 필요 |
| 고혈압 위기 | > 180 | > 120 | 응급 |
| 지표 | 정상 | 주의/전단계 | 위험/진단 |
|---|---|---|---|
| 공복혈당 (FPG) | < 100 mg/dL | 100–125 | ≥ 126 당뇨 |
| HbA1c | < 5.7% | 5.7–6.4% | ≥ 6.5% 당뇨 |
| SpO₂ | ≥ 95% | 91–94% | < 90% 응급 |
| 심박수 (안정) | 60–100 bpm | — | <60 서맥 >100 빈맥 |
| 체온 | 36.1–37.2°C | 37.3–37.9 | ≥38.0 발열 |
| BMI (한국) | 18.5–22.9 | 23–24.9 과체중 | ≥25 비만 |
| 총콜레스테롤 | < 200 mg/dL | 200–239 | ≥240 고콜레스테롤 |
| 구분 | 영문 | 내용 |
|---|---|---|
| S | Subjective | 환자가 말하는 증상 (주소, 현병력) |
| O | Objective | 의사가 측정한 것 (활력징후, 검사 결과) |
| A | Assessment | 의사의 판단 (진단 또는 감별진단) |
| P | Plan | 치료 계획 (처방, 추가 검사, 추적 관찰) |
| 리소스 | 의미 | 사용 예 |
|---|---|---|
| Patient | 환자 기본 정보 | 이름, 생년월일, 성별 |
| Observation | 관측값 | 혈압, 혈당, SpO₂ |
| Condition | 진단 | ICD-10 코드 포함 |
| MedicationRequest | 처방전 | 약물명, 용량, 투여 방법 |
| DiagnosticReport | 검사 보고서 | 영상, 혈액검사 결과 |
| 영상 | 원리 | 주요 활용 | AI 주제 |
|---|---|---|---|
| X-ray | 방사선 투과 | 흉부, 골절 | 폐렴·폐결핵 분류 |
| CT | X-ray 단층 촬영 | 뇌, 폐, 복부 | 암 병변 탐지 |
| MRI | 자기장 공명 | 뇌, 척추, 관절 | 뇌종양 분류 |
| 안저 사진 | 눈 뒷면 촬영 | 당뇨망막병증 | 병변 분류 |
| 피부 사진 | 일반 카메라 | 피부암 | 악성/양성 분류 |
| 법령 | 핵심 내용 | AI 프로젝트 영향 |
|---|---|---|
| 개인정보보호법 | 건강정보 처리 시 명시적 동의 필요 | 환자 데이터 무단 사용 금지 |
| 의료법 제21조 | 의무기록 외부 유출 금지 | 데이터 반출 시 익명화 필수 |
| 의료기기법 | AI 진단 보조 = 의료기기(SaMD) | 식약처 허가 필요 |
| 보건의료빅데이터법 | 공공 의료 데이터 활용 허용(조건부) | 보건의료빅데이터 플랫폼 |
| 기관 | 제공 데이터 | URL |
|---|---|---|
| 공공데이터포털 | 건강검진, 의료기관 현황 | data.go.kr |
| HIRA (건강보험심사평가원) | 진료비 청구, 처방 데이터 | opendata.hira.or.kr |
| NHIS-NSC | 약 100만명 코호트 (건강검진) | nhis.or.kr |
| AIHub | AI 학습용 의료 영상 데이터 | aihub.or.kr |
| Kaggle 헬스케어 | 다양한 의료 데이터셋 | kaggle.com |
| 등급 | 위험도 | 예시 |
|---|---|---|
| 1등급 | 저위험 | 건강관리 앱, 단순 측정 |
| 2등급 | 중위험 | 영상 분석 보조 (현재 대부분 AI) |
| 3등급 | 고위험 | 독립적 진단 결정 보조 → 식약처 허가 필수 |
| 용어 | 영문 | 의미 |
|---|---|---|
| 유병률 | Prevalence | 특정 시점에 질병을 가진 비율 |
| 발생률 | Incidence | 특정 기간 동안 새로 생긴 비율 |
| 민감도 | Sensitivity (Recall) | 실제 환자 중 양성 판정 비율 — 미진단 최소화 |
| 특이도 | Specificity | 실제 정상 중 음성 판정 비율 — 과진단 최소화 |
| 양성예측도 | PPV (Precision) | 양성 판정 중 실제 환자 비율 |
| 황금기준 | Gold Standard | 진단의 기준이 되는 최고 방법 |
| 코호트 | Cohort | 같은 조건으로 묶인 집단 |
| RCT | Randomized Controlled Trial | 무작위 대조군 임상 시험 (근거 최고 수준) |
| 교란변수 | Confounding Variable | 결과에 영향 주는 숨은 변수 |
| 서카디안 리듬 | Circadian Rhythm | 24시간 주기 생체 리듬 |
| 빈맥/서맥 | Tachycardia/Bradycardia | 심박수 100+ / 60- bpm |
| 저산소증 | Hypoxia | 조직 산소 공급 부족 (SpO₂ < 94%) |
| 기업 | 분야 | 대표 제품 |
|---|---|---|
| 루닛 | 흉부 X-ray AI | Lunit INSIGHT CXR |
| 뷰노 | 안저·심전도 AI | VUNO Med |
| JLK | 뇌졸중 AI | JLK-LVO |
| 딥바이오 | 병리 슬라이드 AI | DeepDx |
| 카카오헬스케어 | 디지털 건강 플랫폼 | 파스토 |
| 순위 | 역량 | 핵심 내용 | 왜 중요한가 |
|---|---|---|---|
| ① | 데이터 전처리 | 결측치·이상치·자료형 변환·파생변수 | 분석의 80%는 전처리에서 결정돼요 |
| ② | 탐색적 데이터 분석 (EDA) | 분포 파악, 변수 관계, 그룹 비교 | 방향을 잡지 못하면 분석 자체가 흔들려요 |
| ③ | 시각화 | 상황에 맞는 차트 선택, 가독성 | 발표와 보고서의 핵심이에요 |
| ④ | 통계적 사고 | p-value, 상관관계, 가설 검정 | "높다"가 아니라 "유의미하게 높다"고 말할 수 있어야 해요 |
| ⑤ | 도메인 지식 + 인사이트 | 의료 수치 기준, 임상적 의미 해석 | 코드보다 어렵고, 가장 차별화되는 역량이에요 |
| 역량 | 지금 수준 | 다음 단계 | 도구 |
|---|---|---|---|
| 전처리 | 결측치·이상치 처리 | 피처 엔지니어링 | pandas, sklearn |
| EDA | 기본 집계·그룹화 | 다변수 동시 분석 | pandas, pivot_table |
| 시각화 | seaborn 기본 차트 | Plotly 인터랙티브 | plotly, streamlit |
| 통계 | 기술통계 | 가설 검정, 상관분석 | scipy.stats |
| 도메인 | 임상 수치 기준 | ICD-10, EMR 구조 | 이 가이드 참고 |
| 목적 | 추천 차트 | 코드 | 의료 활용 예 |
|---|---|---|---|
| 분포 보기 | 히스토그램 / KDE | df['sbp'].hist() | 혈압 분포, 위험 기준선 표시 |
| 이상치 탐지 | 박스플롯 | sns.boxplot() | 활동별 심박수 분포 비교 |
| 두 변수 관계 | 산점도 + 추세선 | sns.scatterplot() | BMI vs 혈압, 추세선으로 선형성 확인 |
| 그룹 비교 | 막대그래프 | sns.barplot() | 성별·연령대별 평균 혈당 |
| 상관관계 전체 | 히트맵 | sns.heatmap(corr) | 모든 지표 간 상관 한눈에 |
| 분포 + 중앙값 | 바이올린 플롯 | sns.violinplot() | 진단별 체온 분포 비교 |
| 시계열 변화 | 라인 차트 | plt.plot() | 시간대별 생체 신호 변화 |
| 비율 구성 | 스택 바 / 파이 | df.plot(kind='bar', stacked=True) | 위험 등급 비율 |
| 상황 | 검정 방법 | 코드 |
|---|---|---|
| 두 그룹 평균 비교 | 독립 t-검정 | stats.ttest_ind(A, B) |
| 3개+ 그룹 비교 | ANOVA | stats.f_oneway(A, B, C) |
| 두 수치 변수 관계 | 피어슨 상관 | stats.pearsonr(x, y) |
| 두 범주 변수 독립성 | 카이제곱 검정 | stats.chi2_contingency(ct) |
| 정규분포 확인 | Shapiro-Wilk | stats.shapiro(x) |
| 주의사항 | 잘못된 예 | 올바른 접근 |
|---|---|---|
| 상관 ≠ 인과 | "BMI가 높으면 고혈압이 생긴다" | "BMI와 혈압은 r=0.4의 양의 상관이 있다" |
| 표본 편향 명시 | 특정 연령대만 분석 후 전체 결론 | "이 데이터는 40~60대 비중이 높아 편향 가능성 있음" |
| 통계 ≠ 임상 | "p<0.05이므로 임상적으로 중요하다" | 차이의 크기(effect size)를 함께 보고해야 해요 |
| 이상치 ≠ 오류 | 심박수 180bpm 무조건 제거 | 맥락 확인 — Running 중이면 정상 생리 반응 |
| Raw Data 보존 | 원본 데이터에 직접 DELETE | df_clean = df[조건].copy() — 원본 유지 |
| 한계점 명시 | 분석 결론만 발표 | "데이터 수집 기간, 센서 정확도, 검증 미완료" 명시 |
| 패턴 | 판단 | 처리 |
|---|---|---|
| 심박↑ + 걸음수↑ + Running | 정상 생리 반응 | 보존 — 위험군 아님 |
| 심박↑ + 걸음수=0 + Resting | 센서 오류 가능성 높음 | is_tampered 확인 후 제거 |
| 체온↑ + 심박↑ + 호흡↑ | 실제 발열 — 3중 확인 | 보존 + 위험 알람 대상 |
| SpO₂↓ + 걸음수=0 + 야간 | 수면 무호흡 의심 | 의료 전문가 검토 필요 |
| 항목 | 내용 |
|---|---|
| 데이터 | smoking_health_data.csv — 건강검진 수검자의 생체 지표 + 흡연 여부 |
| 목표 | 흡연자 vs 비흡연자 지표 차이 분석, 의료 가설 5개 검증 |
| 분석 흐름 | EDA → 시각화 → 가설 수립 → 통계 검정 → 인사이트 |
| 다음 단계 | 머신러닝 모델로 흡연 여부 예측 (Step 05) |
| 컬럼 | 의미 | 의료적 의미 |
|---|---|---|
| 나이 | 연령 | 대부분 30~50대 검진자 |
| 키(cm) / 몸무게(kg) / BMI | 신체 계측 | 비만도 판정 기준 |
| 시력 | 시력 측정값 | 이산적 값 (0.1 단위) |
| 충치 | 충치 유무 | 구강 건강 지표 |
| 공복 혈당 | 아침 공복 혈당 | ≥126 → 당뇨 진단 |
| 혈압 | 이완기 혈압 (추정) | 혈관 저항 지표 |
| 중성 지방 | 혈중 트리글리세리드 | ≥150 → 고중성지방혈증 |
| 콜레스테롤 | 총 콜레스테롤 | ≥200 주의, ≥240 이상 |
| 고밀도지단백 (HDL) | 좋은 콜레스테롤 | 높을수록 심혈관 보호 |
| 저밀도지단백 (LDL) | 나쁜 콜레스테롤 | 높을수록 동맥경화 위험 |
| 헤모글로빈 | 혈중 헤모글로빈 | 흡연 관련 핵심 지표 |
| 간 효소율 | ALT 또는 AST | 간 기능 지표 |
| label | 흡연 여부 | 0=비흡연자, 1=흡연자 |
| 변수 | 채우는 방법 | 이유 |
|---|---|---|
| 시력 | 최빈값(mode) | 0.1 단위 이산값 — 평균(0.87)은 실존하지 않는 수치 |
| 공복 혈당 | 나이대별 중앙값 | 나이↑ → 혈당↑ 경향, 오른쪽 치우침(right-skew) 분포 |
| 혈압 | 나이대별 중앙값 | 나이가 혈압에 가장 큰 영향 — 전체 평균은 부정확 |
| 중성 지방 | 나이대별 중앙값 | 극단값(고중성지방) 존재 → 중앙값이 안전 |
| 가설 형태 | 의미 |
|---|---|
| H₀ (귀무가설) | "차이가 없다" — 보수적 입장. 기본 가정 |
| H₁ (대립가설) | "차이가 있다" — 우리가 증명하고 싶은 것 |
| p-value < 0.05 | H₀ 기각, H₁ 채택 → "통계적으로 유의한 차이" |
| 가설 | 내용 | 검정 방법 | 의학적 근거 |
|---|---|---|---|
| 가설 1 | 흡연자 헤모글로빈 > 비흡연자 | 독립 t-검정 | 흡연 시 CO가 산소 운반 방해 → 보상성 적혈구 증가. 흡연 추정의 핵심 바이오마커. |
| 가설 2 | 흡연자 HDL < 비흡연자 | 독립 t-검정 | 흡연이 HDL 합성 억제, 분해 촉진. AHA(미국심장협회) 확립된 사실. 심혈관 위험 증가. |
| 가설 3 | 흡연자 중성 지방 > 비흡연자 | 독립 t-검정 | 흡연 → 인슐린 저항성↑ → LPL 활성 저하 → 중성 지방↑. 대사증후군·동맥경화 위험. |
| 가설 4 | 흡연자 혈압 > 비흡연자 | 독립 t-검정 | 니코틴 → 교감신경 자극 → 혈관 수축, 심박수↑, 혈압↑. 장기 흡연 → 혈관 내피 기능 저하. |
| 가설 5 | BMI 구간과 흡연 여부는 관련 있다 | 카이제곱 검정 | 통념(흡연자=마름)과 달리 실제 검진 데이터에서는 흡연+음주+운동부족 동반 → 비만 비율 높음. |
| 상황 | 검정 방법 | 이유 |
|---|---|---|
| 수치형 vs 두 그룹 비교 (가설 1~4) | 독립표본 t-검정 (equal_var=False) | Welch's t-test: 두 그룹 분산이 다를 때 더 정확 |
| 범주형 vs 범주형 (가설 5) | 카이제곱 검정 | 두 범주 변수의 독립성 검증에 사용 |
| 가설 | 예상 방향 | 통계 결과 | 의학적 해석 |
|---|---|---|---|
| 가설 1 (헤모글로빈) | 흡연자↑ | ✅ 채택 (p<0.001) | 일산화탄소 → 보상성 적혈구 증가. 흡연 추정의 핵심 바이오마커. |
| 가설 2 (HDL) | 흡연자↓ | ✅ 채택 (p<0.001) | 좋은 콜레스테롤 감소 → 심혈관 질환 위험 증가. 금연 후 HDL이 빠르게 회복됨. |
| 가설 3 (중성 지방) | 흡연자↑ | ✅ 채택 | 대사증후군·동맥경화 위험 증가. 흡연의 복합 대사 영향. |
| 가설 4 (혈압) | 흡연자↑ | 결과 확인 | 니코틴 → 일시적 혈압↑. 장기적 혈관 내피 기능 저하. |
| 가설 5 (BMI↔흡연) | 연관 있음 | 카이제곱 결과 확인 | 흡연+음주+운동부족 동반 패턴. "흡연자=마름"은 통념일 뿐. |
| 순위 | 변수 | 방향 | 의학적 해석 | 머신러닝 활용 |
|---|---|---|---|---|
| 🥇 1위 | 헤모글로빈 | 흡연자 ↑ | CO → 보상성 적혈구 증가. 흡연 추정 핵심 지표 | 가장 높은 feature 중요도 예상 |
| 🥈 2위 | HDL (고밀도지단백) | 흡연자 ↓ | 좋은 콜레스테롤 감소 → 심혈관 위험 증가 | 음의 상관 feature |
| 🥉 3위 | 중성 지방 | 흡연자 ↑ | 대사증후군·동맥경화 위험 증가 | 우측 꼬리 이상치 처리 필요 |
| 4위 | 간 효소율 | 흡연자 ↑ (약함) | 흡연이 간에 미치는 부담 | 약한 signal |
| 인사이트 | 내용 |
|---|---|
| 흡연은 단일 위험 인자가 아님 | 헤모글로빈↑, HDL↓, 중성 지방↑을 동시에 악화시켜 심혈관 위험을 복합적으로 높여요 |
| 금연 효과의 빠른 측정 | HDL 증가, 중성 지방 감소를 통해 금연 효과를 수치로 추적 가능해요 |
| 헤모글로빈 = 강력한 흡연 바이오마커 | 향후 ML 예측 모델에서 핵심 feature. 성별 보정 필수 (남성이 여성보다 높음) |
| 검진 시 추가 검사 권고 | 흡연자에게는 폐 검사 외에 HDL·중성 지방 지질 프로필 모니터링 필수 |