CSV·JSON·표 데이터 구조 이해하기
4강. CSV·JSON·표 데이터 구조 이해하기
1. 이번 강의에서 해결할 문제
CSV의 모든 값은 겉으로 문자열처럼 보일 수 있고 한 행의 의미가 불명확하면 중복과 집계 단위가 뒤섞입니다. 데이터 구조와 열 의미를 먼저 정의해야 합니다.
2. 학습 목표
3. 핵심 개념
CSV는 행과 열의 표를 교환하기 좋고 JSON은 중첩 구조와 메타데이터 표현에 유리합니다. 이 프로젝트의 기본 키는 session_id이며 player_id는 가상 식별자입니다. win은 0/1, match_date는 ISO 날짜로 정하고 결측·중복·이상치 학습용 행을 의도적으로 포함합니다.
먼저 구분할 용어
| 용어 | 의미 | 이 데이터의 예 |
|---|---|---|
| 관찰 단위 | 한 행이 나타내는 현실의 한 대상·사건 | 한 플레이어의 완료된 매치 한 건 |
| 행(row) | 같은 관찰 단위의 값 묶음 | S001 매치 결과 |
| 열(column) | 모든 관찰에서 같은 의미로 수집한 항목 | score, win |
| 헤더 | CSV 첫 줄의 열 이름 | session_id,player_id,... |
| 스키마 | 열 이름·타입·허용 범위·결측 규칙의 계약 | score는 숫자이고 결측 가능 |
| 기본 키 | 한 행을 유일하게 식별할 열 또는 열 조합 | session_id |
| 결측치 | 수집되지 않았거나 사용할 수 없는 값 | S006의 빈 score |
관찰 단위를 먼저 정하지 않으면 player_id별 한 행인지, 매치별 한 행인지 알 수 없어 합계와 평균의 분모가 달라집니다. 이 데이터에서는 같은 플레이어 P001이 여러 매치에 나타나는 것이 정상이고, 같은 session_id가 두 번 나타나는 것은 중복 후보입니다.
CSV와 JSON의 가장 작은 비교
session_id,player_id,score
S001,P001,1280
{
"session_id": "S001",
"player_id": "P001",
"score": 1280,
"tags": ["ranked", "win"]
}
CSV는 같은 열을 가진 많은 행을 간결하게 저장하지만 배열처럼 중첩된 tags는 표현하기 불편합니다. JSON은 중첩 구조를 자연스럽게 표현하지만 행·열 집계 전에 평탄화가 필요할 수 있습니다. 형식의 우열이 아니라 데이터 모양과 교환 목적에 따라 선택합니다.
4. 단계별 실습
1. 예제 파일 작성
실행 환경: 코드 편집기
실행 위치: C:\dev\game-data-lab
실행 전 확인: 기존 파일이 있으면 내용을 덮어쓰지 말고 Git diff로 이번 강의 변경 범위를 확인합니다. 실제 개인정보·API Key·토큰은 사용하지 않습니다.
대상 파일: data/raw/game_sessions.csv
작성 전에는 data/raw에 같은 이름의 원본이 있는지 확인합니다. 파일이 있다면 덮어쓰지 말고 별도 학습 브랜치 또는 복사본에서 작업합니다. 작성 후에는 헤더 1줄과 데이터 12행이 있어야 합니다.
session_id,player_id,game_mode,play_minutes,score,win,character,match_date
S001,P001,ranked,18,1280,1,Mage,2026-01-03
S002,P002,ranked,26,970,0,Knight,2026-01-03
S003,P003,casual,14,820,1,Rogue,2026-01-04
S004,P001,casual,21,910,0,Mage,2026-01-05
S005,P004,ranked,32,1410,1,Knight,2026-01-05
S006,P005,casual,17,,0,Rogue,2026-01-06
S007,P006,ranked,44,1530,1,Mage,2026-01-07
S008,P002,casual,11,760,0,Knight,2026-01-07
S009,P007,ranked,29,1190,1,Rogue,2026-01-08
S010,P008,casual,23,880,1,Mage,2026-01-08
S011,P009,ranked,360,1680,1,Knight,2026-01-09
S004,P001,casual,21,910,0,Mage,2026-01-05
표의 값을 읽는 방법
S001행은 P001 플레이어가 ranked 모드에서 18분 플레이하고 1280점으로 승리한 한 매치입니다.S006은score칸이 비어 있어 결측치 후보지만,win=0은 패배를 뜻하는 정상 값입니다.S011의play_minutes=360은 다른 값보다 매우 커 이상치 후보입니다. 오류라고 즉시 삭제하지 않고 실제 장시간 세션인지 수집 문제인지 확인합니다.- 마지막
S004는 앞의 S004와 모든 값이 같아 중복 행 후보입니다.
CSV에는 값의 타입 정보가 별도 저장되지 않습니다. 읽는 도구가 1280을 숫자로 추론할 수 있지만 P001이나 날짜 처리 방식은 도구마다 다를 수 있으므로 데이터 사전과 실제 dtype을 함께 확인합니다.
2. 실행과 결과 확인
실행 환경: Windows PowerShell
실행 위치: C:\dev\game-data-lab
실행 전 확인: Python 코드는 프로젝트의 .venv 인터프리터를 사용하고 입력 파일 경로가 존재하는지 확인합니다.
대상: data/raw/game_sessions.csv과 이 강의가 만드는 출력
Set-Location C:\dev\game-data-lab
Get-Content .\data\raw\game_sessions.csv -TotalCount 5
Import-Csv .\data\raw\game_sessions.csv | Measure-Object
예상 결과: 헤더와 첫 네 행이 보이고 PowerShell은 헤더를 제외한 12개 데이터 행을 셉니다.
행 수: 12
고유 session_id 수: 11
score가 빈 행: S006
중복 후보: S004 두 행
play_minutes 이상치 후보: S011의 360
이 목록은 정제 결론이 아니라 조사할 단서입니다. 특히 360분을 "틀린 값"으로 단정하거나 중복을 바로 삭제하면 실제 장시간 매치나 의도된 재처리를 잃을 수 있습니다.
5. 분석 또는 모델이 동작하는 이유
헤더는 열 이름을 제공하고 각 줄은 같은 스키마의 관찰 한 건입니다. 데이터 사전에는 열 이름, 의미, 예상 타입, 허용 범위, 결측 허용 여부를 기록해야 이후 정제 판단이 일관됩니다.
6. 자주 하는 실수와 해결법
7. 직접 실습
8. 이해 점검 질문 3개
9. 핵심 요약
다음 강의 연결
행과 열의 계약을 정했으므로 5강. NumPy 배열과 벡터에서 숫자 열을 같은 dtype의 배열로 계산하는 방식을 확인합니다.
CSV·JSON·표 데이터 구조 이해하기 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.