필요한 열과 개인정보 구분
90분 안팎
학습 목표
위치·시간의 재식별 가능성을 검토하고 개인 이동 경로 대신 지역별 집계만 사용하는 데이터 사전을 작성합니다.
개념
질문에 필요한 정보만 가져옵니다
교통량과 비의 관계를 묻는 프로젝트에 개인 이름이나 전화번호는 필요하지 않습니다. 많은 열을 수집하면 나중에 쓸 수 있을 것 같지만, 검토할 위험과 관리할 파일도 늘어납니다. 신입이 할 수 있는 첫 조치는 질문과 각 열의 필요성을 연결하고 개인의 이동 경로를 입력 범위에서 제외하는 것입니다. 이 레슨에서는 지역별 일별 집계만 사용하도록 데이터 사전을 작성하고, 불필요한 식별 열이 들어오면 계약 검사에서 거부하도록 확인합니다.
이번 raw 표본은 작성팀이 만든 합성 자료이고 실제 개인 기록을 포함하지 않습니다. 따라서 실제 사람의 정보를 찾아보거나 개인 경로를 내려받는 실습을 하지 않습니다. 검증용 금지 열도 이름 문자열만 추가하는 fixture로 확인합니다. 이 실습의 금지 열 목록은 프로젝트의 제한을 구현한 것이며 실제 데이터의 개인정보 여부를 모두 판정하는 법적 기준이나 인증이 아닙니다.
직접 식별과 결합 위험을 함께 봅니다
이름·전화번호·이메일은 개인과 연결될 수 있는 정보입니다. 장치 식별자도 이름이 없어도 같은 사람의 활동을 이어 볼 수 있게 만들 수 있습니다. 위치·시각을 매우 세밀하게 기록하면 공개된 다른 정보와 결합해 특정인을 추정할 가능성을 검토해야 합니다. 이 레슨의 목적은 위험을 수치로 보장하는 것이 아니라, 분석 질문에 필요 없는 세부 정보를 입력 단계부터 가져오지 않도록 범위를 정하는 것입니다.
이름 열을 지우거나 장치 번호를 해시로 바꿨다는 이유만으로 결과가 안전하다고 단정하지 않습니다. 같은 해시가 여러 날짜에 반복되면 행동을 이어 볼 수 있고 세부 경로가 남아 있으면 다른 정보와 연결할 여지가 있습니다. 이번 질문에는 경로 연결이 필요 없으므로 장치 식별자, 세부 위도·경도, 정확한 시각을 받지 않습니다. 지역 코드와 날짜, 집계 측정값만으로 답할 수 있는 범위를 유지합니다.
지역별 집계도 지역이 매우 작거나 관측 수가 드물면 별도 검토가 필요합니다. “집계했다”는 표현은 검토를 끝내는 증거가 아닙니다. 이번 A와 B는 가상 코드이며 개인 수나 집단 크기를 뜻하지 않습니다. 실제 자료로 교체할 때에는 지역의 공간 범위, 집계 방식, 작은 집단 공개 여부, 제공 조건을 확인하고 공개할 수준을 결정합니다. 필요성 판단과 위험 검토의 근거를 사전에 함께 적습니다.
사전은 열 이름의 번역보다 넓습니다
dictionary.json은 traffic과 weather 각각의 표 정의를 갖습니다. observation_unit은 지역·날짜, timezone은 Asia/Seoul, key는 region과 date입니다. day_boundary에는 현지 시각 00:00 이상 다음 날 00:00 미만을 기록합니다. 후보 키가 정의되어 있어도 원본 중복이 사라지지는 않으므로, 키는 기대하는 단위이고 위반은 점검 결과에서 확인한다는 점을 남깁니다.
columns의 각 열에는 type, unit, nullable을 둡니다. region은 string과 지역 코드, date는 date와 YYYY-MM-DD, vehicle_count는 integer와 대/일, rain_mm은 decimal과 mm/일입니다. region과 date는 nullable=false, 측정값 두 열은 nullable=true로 정합니다. CSV에는 숫자가 글자로 저장되지만 type은 이후 프로그램이 해석해야 할 의미상의 자료형입니다. 표기와 해석을 구분해야 앞자리 0과 소수점이 사라지지 않습니다.
nullable=true는 빈값을 허용한다는 뜻이며 빈값을 0으로 채우라는 뜻이 아닙니다. missing_policy에는 빈 문자열을 미관측으로 유지하고 0과 구분한다고 씁니다. region이나 date가 빈 행은 어떤 관측인지 알 수 없으므로 다른 정책이 필요합니다. 이번 표본에는 그런 행이 없지만 키 열은 비어 있으면 안 된다는 기대를 사전에 고정해 후속 품질 검사로 이어갑니다.
단위가 같아 보이는 두 값도 정의를 확인합니다. vehicle_count는 하루 통행 대수이고 속도 km/h나 개인 수가 아닙니다. rain_mm은 일별 누적 강수량이며 시간당 강수 강도와 다릅니다. 실제 자료에 강수 표시 문자가 있다면 문자 의미를 확인한 뒤 결측 규칙을 새로 정합니다. 이번 합성 표본의 빈 문자열 정의를 실제 기관 자료 전체에 적용하지 않습니다.
열의 필요성을 문장으로 설명합니다
region은 같은 지역 안의 날짜를 비교하고 두 표를 대응시키기 위해 필요합니다. date는 일별 단위를 맞추고 기간을 제한하기 위해 필요합니다. vehicle_count는 비교할 측정값, rain_mm은 강수 여부를 구분할 입력입니다. 이 네 역할 중 하나와 연결되지 않는 새 열이 들어오면 우선 질문에 필요한지 검토합니다. “언젠가 필요할 수 있다”만으로 기본 수집 목록에 추가하지 않습니다.
privacy_review에는 개인 식별자와 세부 위치·시각을 수집하지 않고 지역별 일별 집계만 사용한다는 결정을 적습니다. 그 문장에는 어떤 열을 남겼는지와 어떤 열을 받지 않는지의 근거가 함께 있어야 합니다. 사전을 전달받은 동료가 개인 이동 경로 분석을 요청하면 이번 계약으로는 답할 수 없음을 설명하고 별도 목적과 검토가 필요하다고 말할 수 있어야 합니다.
기계 검사의 범위를 이해합니다
제공된 계약 검증기는 name, phone, email, device_id, latitude, longitude, timestamp라는 열 이름이 사전에 나타나면 PRIVACY 메시지로 거부합니다. 허용된 열 이름과 정확히 일치하는지도 확인합니다. person 같은 다른 이름을 썼다고 개인정보가 없어지는 것은 아닙니다. 검사기는 값의 의미나 외부 자료와의 연결 위험까지 판단하지 않으며, 실제 입력과 사람의 검토가 필요합니다.
fixture 테스트에서는 사전의 복사본에 금지 열 이름을 하나씩 넣고 거부되는지를 확인합니다. 테스트를 통과하려고 금지 목록을 지우거나 검증기 코드를 바꾸지 않습니다. 제출본의 사전은 원본 헤더와 맞아야 합니다. TYPE/UNIT 메시지는 자료형·단위, NULLABLE은 빈값 허용 규칙, GRAIN은 관측 단위, TIMEZONE은 시간대의 불일치를 알려 줍니다. 표시된 표와 열부터 확인합니다.
데이터 사전 작성에서는 JSON의 true와 false를 따옴표로 감싸지 않습니다. "false"는 문자이고 false는 논리값입니다. 검증에서 실패하면 사람이 보기에는 비슷한 표기라도 구조가 다를 수 있음을 살펴봅니다. 쉼표나 중괄호 오류가 나면 JSON 문법부터 복구하고, 그 다음 열 이름과 단위를 점검합니다. 수정 후에는 같은 테스트를 다시 실행해 바뀐 항목과 다른 항목을 함께 확인합니다.
질문·출처·점검과 연결해 인계합니다
질문에는 지역·날짜별 비교라고 쓰고 사전에는 장치·분 단위 경로라고 쓰면 두 문서가 서로 다른 작업을 정의합니다. source의 수집 기간과 원본 날짜, dictionary의 단위, audit의 제외 규칙을 함께 읽고 모순을 고칩니다. 미션은 파일을 많이 만드는 과제가 아니라 네 산출물이 같은 입력과 같은 질문을 설명하게 만드는 과제입니다. 원본 해시와 함께 넘겨야 후속 SQL 모듈도 같은 자료로 출발합니다.
더 읽기의 ER 모델링 장은 대상과 속성의 관계를 설계하는 데 도움을 줍니다. 개인정보 판단을 대신하는 자료로 연결하는 것은 아닙니다. 레슨에서는 질문에 필요한 속성을 골라 사전으로 기록하는 데 집중합니다. 최종 검토에서는 각 열이 질문에 쓰이는 이유, 0과 빈칸의 차이, 금지 열을 거부하는 범위, 사람이 추가로 검토할 한계를 동료에게 설명합니다.
따라하기
사전에서 필요 열만 확인
data-data-contract ZIP의 dictionary.json을 엽니다. traffic은 region/date/vehicle_count, weather는 region/date/rain_mm만 둡니다. weather의 rain_mm.unit에 있는 TODO를 mm/일로 고칩니다. 각 열이 질문에 필요한 이유를 적습니다.
불필요한 열 이름 감지
columns_check.py로 저장해 python3 columns_check.py로 실행합니다. 이 확인은 열 이름의 검사이며 실제 값의 개인정보 여부를 판단하지 않습니다.
allowed = {'region', 'date', 'vehicle_count'}
received = {'region', 'date', 'vehicle_count', 'device_id'}
print('허용 목록 밖:', ','.join(sorted(received - allowed)))실행 결과
허용 목록 밖: device_id
빈값 허용의 논리값 확인
dictionary_check.py로 저장해 python3 dictionary_check.py로 실행합니다. JSON의 true는 따옴표 없는 논리값입니다. 숫자 열의 nullable은 빈값을 0으로 채우라는 뜻이 아닙니다.
import json
meta = json.loads('{"type":"decimal","unit":"mm/일","nullable":true}')
print(meta['type'], meta['unit'])
print('논리값:', isinstance(meta['nullable'], bool))실행 결과
decimal mm/일 논리값: True
미션의 네 산출물 통합 검증
source·dictionary·question·audit를 채운 뒤 ZIP 루트에서 두 명령을 실행합니다. 테스트 10개와 하위 fixture가 통과하고 계약 통과 문구가 나오면 구조 검증 완료입니다. 질문의 적합성과 위험 검토 문장은 별도로 읽고 원본 두 CSV와 함께 다음 모듈로 넘깁니다.
python3 -m unittest discover -s tests -v
python3 contract.py확인 문제
실습
미션 ZIP의 dictionary.json을 완성합니다. 표별 관측 단위·시간대·날짜 경계·후보 키, 열별 타입·단위·빈값 허용, 빈칸 처리, 필요한 열과 세부 개인 경로 제외 근거를 제출합니다. 각 열이 질문에 필요한 이유와 금지 열 이름 검사의 한계를 설명합니다. 미션의 fixture 테스트로 개인 식별 열 거부를 확인합니다.
더 읽기
면접 질문
- 공개 데이터로 만든 그래프의 신뢰성을 확인하는 방법을 설명해 주시면 됩니다.