카카오헬스케어
경력근거: 의료기관별 표준용어 매핑 검증 도구 개발
카카오헬스케어 선행기술연구소 표준기술팀은 R-Alliance 공통 의료 데이터 모델(UDM)을 만들고 유지하며, 공고에 의료기관별 표준용어 매핑 검증 도구 개발을 주 업무로 적었습니다. 참여 병원마다 검사 코드와 단위 관행이 달라 LOINC 매핑 하나가 틀리면 UDM 으로 모인 다기관 수치가 통째로 어긋나고, 이 매핑을 결과값으로 되짚는 일은 여러 병원의 검사 결과가 한곳에 모이는 R-Alliance 에서만 비교 기준이 섭니다. 이 포트폴리오는 병원 결과값의 단위 최빈값과 병원 간 중앙값으로 매핑을 판정하는 Python 파이프라인과 FastAPI 백엔드, 두 담당자가 함께 보는 화면을 보여줍니다. 임상검사의학이나 LOINC 매핑 실무의 전문성은 주장하지 않습니다.
카카오헬스케어 선행기술연구소 표준기술팀은 R-Alliance 공통 의료 데이터 모델(UDM)을 만들고 유지하며, 공고는 의료기관별 표준용어 매핑 검증 도구 개발을 팀의 주 업무로 적었습니다. 병원마다 다른 검사 코드를 LOINC 에 맞춘 매핑이 실제 결과값과 맞는지 되짚는 일이 이 팀의 도구 목록 한가운데에 있습니다.
주요업무는 원천 데이터의 분석·변환·검증·적재 파이프라인이고, 자격요건은 SQL 과 데이터 모델링, 우대사항은 데이터 품질 관리와 검증 시스템 경험입니다. 병원 매핑표와 검사 결과, LOINC 용어표 세 표를 잇고 병원별 결과값 중앙값을 내 견주는 계산을 PostgreSQL 과 Python 위에 둡니다.
공고의 기술 스택은 Python·FastAPI·Next.js·PostgreSQL·GCP·Docker·Kubernetes 이고, AI Coding Agent 와 LLM 으로 데이터 처리를 자동화한 경험을 우대합니다. 2주차에 GCP 에 올리고, 3주차에 걸린 매핑의 후보 LOINC 코드를 Claude 가 고르게 한 뒤 확정한 수정을 FHIR ConceptMap 으로 내보냅니다.
R-Alliance(여러 병원이 공통 데이터 모델로 검사·진료 데이터를 모으는 다기관 연구 연합)에 참여한 병원은 저마다 붙인 검사 코드(공복혈당 GLU-F, 크레아티닌 CHEM-CR 같은)를 LOINC 표준용어에 매핑해 공통 데이터 모델로 보냅니다. 이 관리자 페이지는 병원별 매핑표, 그 병원이 실제로 낸 검사 결과값과 단위, LOINC 용어표의 검체 계통·예시 UCUM 단위(의료 검사 단위를 적는 국제 규칙)·상태를 받아 매핑마다 다섯 판정 중 하나를 붙입니다. 결과 단위의 최빈값을 대소문자 차이 없이 LOINC 예시 단위와 견주고, 병원이 적은 검체를 대응표로 LOINC 검체 계통에 맞춰 보며, 같은 LOINC 코드로 묶인 병원마다 결과값 중앙값을 내 다른 병원과 5배 넘게 벌어진 매핑을 찾습니다. 카카오헬스케어 표준용어 담당자는 이 판정으로 어느 병원에 수정을 요청할지 정하고, 참여 병원 진단검사·의료정보 담당자는 자기 병원에서 걸린 매핑을 열어 고칩니다.
R-Alliance 병원마다 다르게 붙은 검사 코드를 LOINC 에 맞추는 카카오헬스케어 표준용어 담당자와, 자기 병원 매핑 결과를 확인해 고쳐 주는 참여 병원 진단검사·의료정보 담당자. 같은 매핑 검증 화면을 보고 어느 매핑을 누가 고칠지 정한다
지금 매핑 검토는 매핑표 한 장을 놓고 병원 검사 이름과 LOINC 이름이 비슷한지 보는 데서 멈춥니다. 매핑이 맞는지는 이름보다 그 코드로 실제로 흘러온 결과값이 더 잘 말해 줍니다. 병원 결과에는 단위와 값이 이미 남아 있어서, 단위 최빈값과 병원 간 중앙값을 LOINC 정의와 견주면 이름만으로는 안 보이던 mmol/L 공복혈당이나 단위 칸만 mg/dL 로 적힌 크레아티닌이 드러납니다.
표준용어 담당자가 병원별 매핑표·검사 결과·LOINC 용어표 세 파일을 올리면 매핑마다 다섯 판정 중 하나와 결과 단위 최빈값, 병원 중앙값, 다른 병원 중앙값이 서는 관리자 페이지입니다. 단위 문자열의 대소문자 차이를 없애는 처리, 검체 이름을 LOINC 검체 계통으로 바꾸는 대응표, 병원별 중앙값을 낸 뒤 다른 병원 중앙값과 배수를 재는 계산, 판정 차례가 이 주에 들어갑니다.
참여 병원이 월별 검사 결과 파일을 올리면 FastAPI 가 받아 PostgreSQL 에 적재하고 판정을 다시 돌려, 지난달과 판정이 달라진 매핑만 이력으로 남깁니다. 매핑 하나를 펼치면 병원별 결과값 분포를 상자 그림으로 보여주고, 병원 열 곳의 매핑 300건에는 제가 LOINC 정의를 읽고 판정을 먼저 붙여 두어 자동 판정과 다른 매핑을 찾습니다. API 와 배치는 Docker 이미지로 묶어 GCP Cloud Run 과 Cloud SQL 에 올립니다.
단위나 검체로 걸린 매핑에 Claude 가 LOINC 용어표에서 후보 코드를 세 개까지 고르면, 후보의 검체 계통과 예시 단위가 병원 값과 맞는지 규칙이 다시 보고 통과한 후보만 화면에 올립니다. 표준용어 담당자가 고른 수정은 FHIR ConceptMap 리소스로 내보내 참여 병원 담당자에게 전달하고, 월별 재판정 배치는 GKE 의 CronJob 으로 돌립니다.
표준용어 담당자가 병원 10곳의 매핑표와 검사 결과를 올리면 mmol/L 로 결과를 낸 H07 공복혈당 LAB-GLU-01 이 단위 불일치에, 단위 칸은 mg/dL 인데 중앙값이 79 인 H11 크레아티닌 CHEM-CR 이 다른 병원 중앙값 0.92 와 85배 넘게 벌어져 값 범위 어긋남에 섭니다.
참여 병원 담당자가 자기 병원 매핑 하나를 펼쳐 결과 단위별 건수, 병원 중앙값과 다른 병원 중앙값, 매핑된 LOINC 코드의 검체 계통과 상태를 읽고 무엇을 고칠지 정합니다.
검체를 적지 않은 칼륨 매핑, 값이 비어 있는 검사 결과, 소문자로 적은 mg/dl, LOINC 용어표에 없는 오타 코드 2951-8 을 한 번에 넣어도 매핑마다 판정이 하나로 정해집니다. 값 칸에 '>500'·'음성' 같은 글자가 든 결과는 중앙값에서 빼고, 매핑을 펼치면 그 원문을 따로 보여줍니다.
표준용어 담당자가 값 범위 기준을 5배에서 3배로 바꿔 보면 신장 전문 병원 H08 의 요단백 매핑이 3.67배 차이로 값 범위에 넘어가, 기준값 하나가 정상 매핑과 단위 누락을 가르는 자리를 화면에서 확인합니다.
위 수치는 더미데이터 자가채점이며, 이 판정이 실제 매핑 오류를 얼마나 잡는지는 R-Alliance 참여 병원의 실제 매핑표와 검사 결과, 표준용어 담당자의 검토 결과가 있어야 측정됩니다. 용어표는 Loinc.csv 의 열 이름을 그대로 쓰므로 실제 배포 파일로 바꿔 끼우는 데 코드 수정이 들지 않습니다.
판정 규칙과 정답을 모두 제가 정했습니다. 매핑 300건의 정답도 진단검사의학과 담당자가 아니라 제가 LOINC 정의를 읽고 붙인 것이라, 시연이 보여주는 범위는 규칙이 적힌 대로 돈다는 데까지이고 면접에서도 그 선을 넘겨 말하지 않습니다.
소문자 mg/dl 을 대소문자 그대로 견주는 구현은 H04 크레아티닌을 단위 불일치로 빼고, 그 여파로 H01·H02 크레아티닌의 비교 기준이 H11 쪽으로 끌려가 정상 매핑 둘이 값 범위로 뒤집힙니다. 이 연쇄가 테스트에서 드러나도록 H04 매핑의 기대 출력을 묶어 두었습니다.
병원 간 수치 차이는 환자군만으로도 3~4배 벌어질 수 있어 기준을 5배로 잡았고, 더미의 신장 전문 병원 H08 요단백(3.67배)이 그 자리입니다. 투석 환자가 몰린 병원처럼 5배를 넘는 정상 병원도 있을 수 있어, 환자군 차이인지 매핑 오류인지는 참여 병원 담당자가 값 분포를 보고 정합니다.
LOINC 용어표 더미의 상태 값은 시연용으로 제가 적은 것이라 17855-8 의 실제 상태와 다를 수 있고, 검체 대응표도 제가 LOINC 문서를 읽고 짠 것이라 표준용어 담당자의 확인이 필요합니다. 실제 판정은 LOINC 배포 파일의 STATUS 열을 그대로 읽게 둡니다.
오타 코드와 폐기 코드가 같은 판정에 묶여 고칠 사람이 흐려집니다. 오타는 병원이 고치고 폐기는 표준용어 담당자가 대체 코드를 알려줘야 하므로, 펼침에서는 '용어표에 없음'과 'DEPRECATED'를 다른 문구로 보여줍니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
R-Alliance 참여 병원이 자기 검사 코드에 붙인 LOINC 매핑표입니다. 병원이 검체를 비워 둔 매핑, LOINC 코드를 옮겨 적다 끝자리를 틀린 매핑, 단백뇨 환자가 많은 신장 전문 병원의 요단백 매핑을 일부러 넣었습니다.
| mapping_id | hospital_id | local_code | local_name | specimen | loinc_code | mapped_at |
|---|---|---|---|---|---|---|
| MAP-H01-0003 | H01 | GLU-F | 공복혈당 | 혈청 | 2345-7 | 2026-06-12 |
| MAP-H01-0004 | H01 | CR | 크레아티닌 | 혈청 | 2160-0 | 2026-06-12 |
| MAP-H01-0009 | H01 | U-PRO | 요단백 정량 | 소변 | 2888-6 | 2026-06-12 |
| MAP-H02-0011 | H02 | CHEM-GLU | 포도당 | 혈장 | 2345-7 | 2026-07-03 |
| MAP-H02-0014 | H02 | CHEM-CRE | Creatinine | 혈청 | 2160-0 | 2026-07-03 |
아래 JSON Schema 에 맞는 병원 검사 코드 LOINC 매핑 행을 더 만들어 주세요. {"type":"object","properties":{"mapping_id":{"type":"string"},"hospital_id":{"type":"string","description":"R-Alliance 참여 병원 번호(H01~H17)입니다."},"local_code":{"type":"string","description":"병원이 자체로 붙인 검사 코드입니다."},"local_name":{"type":"string"},"specimen":{"type":["string","null"],"enum":["혈청","혈장","소변","전혈",null],"description":"병원이 적은 검체입니다. 적지 않았으면 null 입니다."},"loinc_code":{"type":"string","description":"병원이 매핑한 LOINC 코드입니다."},"mapped_at":{"type":"string","description":"매핑을 마지막으로 고친 날짜(YYYY-MM-DD)입니다."}},"required":["mapping_id","hospital_id","local_code","local_name","specimen","loinc_code","mapped_at"]} 혈당·크레아티닌·전해질·간수치·당화혈색소·소변 검사처럼 병원이 흔히 내는 화학·혈액 검사를 쓰고, 같은 검사를 병원마다 다른 local_code 와 local_name(한글·영문·약어)으로 적습니다. loinc_code 는 실제 LOINC 코드 형식(숫자-검증숫자)을 씁니다. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) specimen 이 null 인 매핑, (2) 소변 검사를 Ser/Plas 코드에 매핑한 경우, (3) 몰 농도로 결과를 내는 병원이 질량 농도 코드에 매핑한 경우, (4) LOINC 코드 끝자리를 잘못 옮겨 적은 코드, (5) 같은 병원이 같은 검사를 두 코드로 나눠 매핑한 경우. 생성한 행은 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"mapping_id":{"type":"string"},"hospital_id":{"type":"string","description":"R-Alliance 참여 병원 번호(H01~H17)입니다."},"local_code":{"type":"string","description":"병원이 자체로 붙인 검사 코드입니다."},"local_name":{"type":"string"},"specimen":{"type":["string","null"],"enum":["혈청","혈장","소변","전혈",null],"description":"병원이 적은 검체입니다. 적지 않았으면 null 입니다."},"loinc_code":{"type":"string","description":"병원이 매핑한 LOINC 코드입니다."},"mapped_at":{"type":"string","description":"매핑을 마지막으로 고친 날짜(YYYY-MM-DD)입니다."}},"required":["mapping_id","hospital_id","local_code","local_name","specimen","loinc_code","mapped_at"]}참여 병원이 공통 데이터 모델로 보낸 검사 결과입니다. 병원 LIS(검사 정보 시스템)에서 내려받은 값과 단위를 손대지 않고 두어, 단위를 소문자로 적은 병원과 값이 비어 있는 결과가 섞여 있습니다.
| result_id | hospital_id | local_code | value | unit | resulted_at |
|---|---|---|---|---|---|
| LR-0101 | H01 | GLU-F | 98 | mg/dL | 2026-09-14T08:12:00+09:00 |
| LR-0102 | H01 | CR | 0.92 | mg/dL | 2026-09-14T08:12:00+09:00 |
| LR-0103 | H01 | U-PRO | 15 | mg/dL | 2026-09-14T09:40:00+09:00 |
| LR-0201 | H02 | CHEM-GLU | 104 | mg/dL | 2026-09-15T10:05:00+09:00 |
| LR-0202 | H02 | CHEM-GLU | — | mg/dL | 2026-09-15T10:31:00+09:00 |
아래 JSON Schema 에 맞는 병원 검사 결과 행을 더 만들어 주세요. {"type":"object","properties":{"result_id":{"type":"string"},"hospital_id":{"type":"string"},"local_code":{"type":"string"},"value":{"type":["number","null"],"description":"검사 결과 수치입니다. 결과가 보고되지 않았으면 null 입니다."},"unit":{"type":["string","null"],"description":"병원이 적은 그대로의 단위 문자열입니다."},"resulted_at":{"type":"string","description":"+09:00 오프셋이 붙은 ISO 8601 시각입니다."}},"required":["result_id","hospital_id","local_code","value","unit","resulted_at"]} 같은 병원·같은 local_code 의 결과는 한 단위로 나오는 것이 기본이고, 값은 그 검사의 성인 참고 범위 안팎에 둡니다(공복혈당 70~130 mg/dL, 크레아티닌 0.6~1.3 mg/dL). 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) value 가 null 인 결과, (2) 단위를 mg/dl 처럼 소문자로 적은 결과, (3) 몰 농도(mmol/L·umol/L)로 결과를 내는 병원, (4) 단위 칸은 mg/dL 인데 값이 umol/L 크기(70~110)인 크레아티닌, (5) 한 병원·검사 코드 안에서 단위가 두 가지로 섞인 경우. 생성한 행은 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"result_id":{"type":"string"},"hospital_id":{"type":"string"},"local_code":{"type":"string"},"value":{"type":["number","null"],"description":"검사 결과 수치입니다. 결과가 보고되지 않았으면 null 입니다."},"unit":{"type":["string","null"],"description":"병원이 적은 그대로의 단위 문자열입니다."},"resulted_at":{"type":"string","description":"+09:00 오프셋이 붙은 ISO 8601 시각입니다."}},"required":["result_id","hospital_id","local_code","value","unit","resulted_at"]}판정 기준이 되는 LOINC 용어표 일부입니다. LOINC 배포 파일의 열 가운데 이름·성분·검체 계통·예시 UCUM 단위·상태만 옮겼고, 상태 값은 시연을 위해 작성자가 정했습니다.
| loinc_code | long_common_name | component | system | example_ucum_units | status |
|---|---|---|---|---|---|
| 2345-7 | Glucose [Mass/volume] in Serum or Plasma | Glucose | Ser/Plas | ["mg/dL"] | ACTIVE |
| 14749-6 | Glucose [Moles/volume] in Serum or Pla… | Glucose | Ser/Plas | ["mmol/L"] | ACTIVE |
| 2160-0 | Creatinine [Mass/volume] in Serum or P… | Creatinine | Ser/Plas | ["mg/dL"] | ACTIVE |
| 14682-9 | Creatinine [Moles/volume] in Serum or … | Creatinine | Ser/Plas | ["umol/L"] | ACTIVE |
| 2885-2 | Protein [Mass/volume] in Serum or Plasma | Protein | Ser/Plas | ["g/dL"] | ACTIVE |
아래 JSON Schema 에 맞는 LOINC 용어표 행을 더 만들어 주세요. {"type":"object","properties":{"loinc_code":{"type":"string"},"long_common_name":{"type":"string"},"component":{"type":"string"},"system":{"type":"string","description":"LOINC 검체 계통입니다(Ser/Plas·Urine·Bld 등)."},"example_ucum_units":{"type":"array","items":{"type":"string"},"description":"이 코드의 결과에 쓰는 UCUM 예시 단위 목록입니다."},"status":{"type":"string","enum":["ACTIVE","TRIAL","DISCOURAGED","DEPRECATED"]}},"required":["loinc_code","long_common_name","component","system","example_ucum_units","status"]} 병원 화학·혈액·소변 검사에서 흔히 쓰는 코드를 고르고, long_common_name 은 LOINC 의 'Component [Property] in System' 꼴을 따릅니다. 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) 같은 성분인데 질량 농도와 몰 농도로 코드가 갈리는 쌍, (2) 같은 성분인데 Ser/Plas 와 Urine 으로 검체 계통이 갈리는 쌍, (3) status 가 DEPRECATED 또는 DISCOURAGED 인 코드, (4) example_ucum_units 에 단위가 두 개 이상인 코드. 생성한 행은 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"loinc_code":{"type":"string"},"long_common_name":{"type":"string"},"component":{"type":"string"},"system":{"type":"string","description":"LOINC 검체 계통입니다(Ser/Plas·Urine·Bld 등)."},"example_ucum_units":{"type":"array","items":{"type":"string"},"description":"이 코드의 결과에 쓰는 UCUM 예시 단위 목록입니다."},"status":{"type":"string","enum":["ACTIVE","TRIAL","DISCOURAGED","DEPRECATED"]}},"required":["loinc_code","long_common_name","component","system","example_ucum_units","status"]}| Python | 단위 최빈값, 검체 대응, 병원별 중앙값의 중앙값과 배수 계산, 사유 순서를 담은 판정 엔진의 언어입니다. |
| FastAPI | 세 파일을 받아 매핑별 판정을 돌려주는 API 이고, 2주차에 병원 월별 결과 파일 수신 엔드포인트를 더합니다. |
| PostgreSQL | 매핑표·검사 결과·LOINC 용어표 세 테이블을 병원 번호와 검사 코드로 잇고, 병원별 중앙값을 percentile_cont 로 냅니다. |
| SQL·데이터 모델링 | 매핑 하나에 결과가 여러 건 딸리는 일대다 구조와, 병원 데이터와 떼어 둔 LOINC 기준 테이블을 설계합니다. |
| TypeScript·Next.js | 판정별 매핑 표, 병원 목록 사이드바, 매핑 펼침과 2주차 상자 그림을 그리는 관리자 화면입니다. |
| GCP | 2주차부터 Cloud Run 과 Cloud SQL 에 올려 참여 병원 담당자가 같은 주소로 자기 병원 매핑을 봅니다. |
| Docker·Kubernetes | API 와 판정 배치를 Docker 이미지로 만들고, 3주차에 월별 재판정 배치를 GKE CronJob 으로 돌립니다. |
| FHIR·LOINC | LOINC 용어표의 검체 계통·예시 UCUM 단위·상태를 판정 기준으로 쓰고, 3주차에 확정한 수정을 FHIR ConceptMap 으로 내보냅니다. |
| LLM·AI Coding Agent | 3주차에 Claude 가 걸린 매핑의 후보 LOINC 코드를 고르고, 개발 중에는 Claude Code 로 판정 규칙의 경계 테스트를 늘립니다. |
✗ fail → 정상인 크레아티닌 병원이 값 범위로 걸리면 이미 걸린 매핑을 기준에서 빼는 단계부터 살피고, H03 처럼 두 사유에 걸린 매핑이 담당자 예상과 다른 사유로 뜨면 검체와 단위의 순서를 다시 정합니다.
✓ pass → 표준용어 담당자가 이 표를 들고 H07·H11 담당자에게 무엇을 고쳐 달라고 할지 말할 수 있으면 여기서 멈춰도 됩니다. 이어서 만든다면 월별 결과 적재와 GCP 배포가 다음 차례입니다.
✗ fail → 같은 파일 재적재에서 이력이 늘면 결과 행의 중복 적재부터 막고, 후보 제안은 미룹니다.
✓ pass → 후보 코드 제안과 수정 파일 내보내기로 3주차를 엽니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
verdict사유 라벨 · mapping_id + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
폐기된 LOINC 코드에 매핑됨폐기·없는 코드검체가 LOINC 와 다름검체 불일치결과 단위가 LOINC 와 안 맞음단위 불일치다른 병원과 값 범위가 어긋남값 범위 이탈매핑 그대로 사용그대로 사용병원 검사 코드의 LOINC 매핑 하나가 코드 상태, 검체 계통, 결과 단위 최빈값, 다른 병원과의 중앙값 배수를 거쳐 어떤 판정을 받는지 남기는 형식입니다. 판정은 규칙이 정하고, 3주차부터 걸린 매핑의 후보 코드만 모델이 고릅니다.
{"type":"object","properties":{"mapping_id":{"type":"string"},"hospital_id":{"type":"string"},"local_code":{"type":"string"},"loinc_code":{"type":"string"},"verdict":{"type":"string","enum":["매핑 그대로 사용","결과 단위가 LOINC 와 안 맞음","검체가 LOINC 와 다름","다른 병원과 값 범위가 어긋남","폐기된 LOINC 코드에 매핑됨"]},"unit_mode":{"type":["string","null"],"description":"같은 hospital_id·local_code 의 lab_results.unit 을 대소문자 구분 없이 센 최빈값을 UCUM 표기로 적은 값입니다."},"expected_units":{"type":"array","items":{"type":"string"},"description":"매핑된 loinc_code 의 example_ucum_units 입니다. 용어표에 코드가 없으면 빈 배열입니다."},"specimen":{"type":["string","null"]},"loinc_system":{"type":["string","null"]},"loinc_status":{"type":["string","null"]},"hospital_median":{"type":["number","null"],"description":"같은 hospital_id·local_code 의 lab_results.value 중 null 을 뺀 값의 중앙값입니다."},"other_median":{"type":["number","null"],"description":"같은 loinc_code 로 매핑된 다른 hospital_id 마다 낸 중앙값들의 중앙값입니다. 폐기·검체·단위로 이미 걸린 매핑은 빼고, 남은 다른 병원이 없으면 null 입니다."},"median_ratio":{"type":["number","null"],"minimum":1,"description":"hospital_median 과 other_median 중 큰 값을 작은 값으로 나눈 배수(소수 둘째 자리)입니다. 한쪽이 null 이면 null 입니다."},"evidence":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"agg":{"type":["string","null"]},"value":{}},"required":["field","value"]}},"summary":{"type":"string"},"hedge":{"type":["string","null"]}},"required":["mapping_id","hospital_id","local_code","loinc_code","verdict","unit_mode","expected_units","hospital_median","other_median","median_ratio","evidence","summary"]}[
{
"mapping_id": "MAP-H04-0015",
"hospital_id": "H04",
"local_code": "CREA",
"loinc_code": "2160-0",
"verdict": "매핑 그대로 사용",
"unit_mode": "mg/dL",
"expected_units": [
"mg/dL"
],
"specimen": "혈청",
"loinc_system": "Ser/Plas",
"loinc_status": "ACTIVE",
"hospital_median": 1.04,
"other_median": 0.92,
"median_ratio": 1.13,
"evidence": [
{
"field": "unit",
"value": "mg/dl"
},
{
"field": "example_ucum_units",
"value": [
"mg/dL"
]
},
{
"field": "value",
"value": 1.04
},
{
"field": "value",
"value": 0.92
},
{
"field": "value",
"value": 0.85
},
{
"field": "value",
"value": 77
},
{
"field": "value",
"value": 81
}
],
"summary": "병원이 적은 mg/dl 은 대소문자만 다른 mg/dL 이라 2160-0 의 예시 단위와 같고, 중앙값 1.04 가 다른 병원 중앙값 0.92 와 비슷합니다.",
"hedge": "다른 병원 중앙값은 H01 0.92, H02 0.85, H11 79 세 병원 중앙값의 중앙값이라 H11 한 곳이 크게 벗어나도 0.92 로 섭니다."
},
{
"mapping_id": "MAP-H09-0006",
"hospital_id": "H09",
"local_code": "K",
"loinc_code": "2823-3",
"verdict": "매핑 그대로 사용",
"unit_mode": "mmol/L",
"expected_units": [
"mmol/L"
],
"specimen": null,
"loinc_system": "Ser/Plas",
"loinc_status": "ACTIVE",
"hospital_median": 4.3,
"other_median": null,
"median_ratio": null,
"evidence": [
{
"field": "specimen",
"value": null
},
{
"field": "unit",
"value": "mmol/L"
},
{
"field": "example_ucum_units",
"value": [
"mmol/L"
]
},
{
"field": "value",
"value": 4.3
}
],
"summary": "결과 단위 mmol/L 이 2823-3 의 예시 단위와 같아 매핑을 그대로 씁니다.",
"hedge": "병원이 검체를 적지 않아 검체 비교를 건너뛰었고, 같은 LOINC 코드를 쓰는 다른 병원이 없어 값 범위도 견주지 못했습니다. 참여 병원 담당자에게 검체를 채워 달라고 요청할 매핑입니다."
},
{
"mapping_id": "MAP-H08-0007",
"hospital_id": "H08",
"local_code": "U-PROT",
"loinc_code": "2888-6",
"verdict": "매핑 그대로 사용",
"unit_mode": "mg/dL",
"expected_units": [
"mg/dL"
],
"specimen": "소변",
"loinc_system": "Urine",
"loinc_status": "ACTIVE",
"hospital_median": 55,
"other_median": 15,
"median_ratio": 3.67,
"evidence": [
{
"field": "value",
"value": 52
},
{
"field": "value",
"value": 58
},
{
"field": "value",
"value": 15
},
{
"field": "unit",
"value": "mg/dL"
}
],
"summary": "신장 전문 병원의 요단백 중앙값 55 가 같은 2888-6 을 쓰는 H01 중앙값 15 보다 3.67배 높지만 5배 기준 안쪽이라 매핑을 그대로 씁니다.",
"hedge": "단백뇨 환자가 몰린 병원이라 값이 높은 것으로 봅니다. 기준을 3배로 낮추면 이 정상 매핑이 값 범위로 넘어갑니다."
},
{
"mapping_id": "MAP-H07-0012",
"hospital_id": "H07",
"local_code": "LAB-GLU-01",
"loinc_code": "2345-7",
"verdict": "결과 단위가 LOINC 와 안 맞음",
"unit_mode": "mmol/L",
"expected_units": [
"mg/dL"
],
"specimen": "혈청",
"loinc_system": "Ser/Plas",
"loinc_status": "ACTIVE",
"hospital_median": 5.85,
"other_median": 98,
"median_ratio": 16.75,
"evidence": [
{
"field": "unit",
"value": "mmol/L"
},
{
"field": "unit",
"agg": "count",
"value": 2
},
{
"field": "example_ucum_units",
"value": [
"mg/dL"
]
},
{
"field": "value",
"value": 5.6
},
{
"field": "value",
"value": 6.1
},
{
"field": "result_id",
"value": "LR-0202"
},
{
"field": "value",
"value": null
}
],
"summary": "결과 2건이 모두 mmol/L 인데 매핑된 2345-7 은 mg/dL 로 적는 질량 농도 코드입니다.",
"hedge": "몰 농도 공복혈당은 14749-6 이 따로 있어 매핑 코드를 바꾸는 쪽일 가능성이 큽니다. 다른 병원 중앙값 98 은 H01 98, H02 104, H04 91 로 냈고, H02 의 LR-0202 는 값이 비어 있어 뺐습니다. 값으로도 16배 넘게 벌어지지만 단위가 먼저 판정됩니다."
},
{
"mapping_id": "MAP-H03-0008",
"hospital_id": "H03",
"local_code": "UA-PRO",
"loinc_code": "2885-2",
"verdict": "검체가 LOINC 와 다름",
"unit_mode": "mg/dL",
"expected_units": [
"g/dL"
],
"specimen": "소변",
"loinc_system": "Ser/Plas",
"loinc_status": "ACTIVE",
"hospital_median": 12,
"other_median": null,
"median_ratio": null,
"evidence": [
{
"field": "specimen",
"value": "소변"
},
{
"field": "system",
"value": "Ser/Plas"
},
{
"field": "loinc_code",
"value": "2885-2"
}
],
"summary": "병원은 소변 검체로 적었는데 매핑된 2885-2 는 혈청·혈장 단백 코드입니다.",
"hedge": "결과 단위 mg/dL 도 2885-2 의 예시 단위 g/dL 와 다르지만 검체가 먼저 판정됩니다. 소변 단백은 2888-6 이 따로 있습니다."
},
{
"mapping_id": "MAP-H11-0041",
"hospital_id": "H11",
"local_code": "CHEM-CR",
"loinc_code": "2160-0",
"verdict": "다른 병원과 값 범위가 어긋남",
"unit_mode": "mg/dL",
"expected_units": [
"mg/dL"
],
"specimen": "혈청",
"loinc_system": "Ser/Plas",
"loinc_status": "ACTIVE",
"hospital_median": 79,
"other_median": 0.92,
"median_ratio": 85.87,
"evidence": [
{
"field": "value",
"value": 77
},
{
"field": "value",
"value": 81
},
{
"field": "value",
"value": 0.92
},
{
"field": "value",
"value": 0.85
},
{
"field": "value",
"value": 1.04
},
{
"field": "unit",
"value": "mg/dL"
}
],
"summary": "이 병원 크레아티닌 중앙값 79 가 같은 2160-0 을 쓰는 다른 병원 중앙값 0.92 와 85배 넘게 벌어졌습니다.",
"hedge": "크레아티닌 79 umol/L 는 약 0.89 mg/dL 라서, 값은 umol/L 로 나오는데 단위 칸만 mg/dL 로 적힌 것으로 보입니다. 단위 칸만 보면 맞는 매핑이라 이름과 단위만 견주는 검토로는 드러나지 않습니다."
},
{
"mapping_id": "MAP-H05-0020",
"hospital_id": "H05",
"local_code": "HBA1C-2",
"loinc_code": "17855-8",
"verdict": "폐기된 LOINC 코드에 매핑됨",
"unit_mode": "%",
"expected_units": [
"%"
],
"specimen": "전혈",
"loinc_system": "Bld",
"loinc_status": "DEPRECATED",
"hospital_median": 6.4,
"other_median": null,
"median_ratio": null,
"evidence": [
{
"field": "loinc_code",
"value": "17855-8"
},
{
"field": "status",
"value": "DEPRECATED"
}
],
"summary": "매핑된 17855-8 의 상태가 DEPRECATED 입니다.",
"hedge": "같은 병원의 HBA1C 는 4548-4 에 매핑돼 있어, 두 검사 코드가 같은 검사를 가리키는지 병원 담당자가 확인합니다. 상태 값은 더미 용어표 기준입니다."
},
{
"mapping_id": "MAP-H14-0002",
"hospital_id": "H14",
"local_code": "NA",
"loinc_code": "2951-8",
"verdict": "폐기된 LOINC 코드에 매핑됨",
"unit_mode": "mmol/L",
"expected_units": [],
"specimen": "혈청",
"loinc_system": null,
"loinc_status": null,
"hospital_median": 139,
"other_median": null,
"median_ratio": null,
"evidence": [
{
"field": "loinc_code",
"value": "2951-8"
},
{
"field": "loinc_code",
"agg": "count",
"value": 0
}
],
"summary": "매핑된 2951-8 을 LOINC 용어표에서 찾지 못했습니다.",
"hedge": "나트륨 혈청 코드 2951-2 를 옮겨 적다 끝자리를 틀린 것으로 보입니다. 용어표에 없는 코드는 폐기 코드와 같이 다시 매핑할 대상으로 둡니다."
}
][자동 검증 · 코드가 판정합니다] 1. verdict 가 매핑 그대로 사용·결과 단위가 LOINC 와 안 맞음·검체가 LOINC 와 다름·다른 병원과 값 범위가 어긋남·폐기된 LOINC 코드에 매핑됨 다섯 값 중 하나인지 확인합니다. 2. mapping_id·hospital_id·local_code·loinc_code·verdict·unit_mode·expected_units·hospital_median·other_median·median_ratio·evidence·summary 필드가 빠짐없이 존재하는지 확인합니다. 3. median_ratio 가 null 이 아니면 1 이상인지 확인합니다. 4. hospital_median 을 같은 hospital_id·local_code 의 lab_results.value 중 null 을 뺀 값의 중앙값으로, other_median 을 같은 loinc_code 로 매핑된 다른 hospital_id 마다 낸 중앙값들의 중앙값으로, median_ratio 를 두 값 중 큰 값을 작은 값으로 나눈 배수로 다시 계산합니다. other_median 을 낼 때는 폐기·검체·단위로 이미 걸린 매핑의 값을 뺍니다. 5. term_mappings.loinc_code 를 loinc_concepts 에서 못 찾거나 찾은 행의 status 가 DEPRECATED 이면 verdict 는 폐기된 LOINC 코드에 매핑됨입니다. 6. 앞 조건에 걸리지 않고 specimen 이 null 이 아니며 대응표(혈청→Ser·Ser/Plas, 혈장→Plas·Ser/Plas, 소변→Urine, 전혈→Bld)로 바꾼 값에 loinc_concepts.system 이 없으면 verdict 는 검체가 LOINC 와 다름입니다. 7. 앞 조건에 걸리지 않고 대소문자를 구분하지 않은 unit 최빈값이 example_ucum_units 에 없으면 verdict 는 결과 단위가 LOINC 와 안 맞음입니다. 8. 앞 조건에 걸리지 않고 median_ratio 가 5 를 넘으면 verdict 는 다른 병원과 값 범위가 어긋남이고, 어느 조건에도 걸리지 않으면 매핑 그대로 사용입니다. 9. evidence 의 field 이름이 세 데이터셋 중 하나에 있는 컬럼인지 대조합니다. 10. evidence 의 value 가 수록된 행의 원문 값과 같은지 확인합니다. 여러 행을 센 수는 agg 를 적습니다. 11. summary 가 존댓말로 끝나는지 확인합니다. [확정 카드 판정식과 다른 점] 카드는 다른 병원 값을 '같은 loinc_code 로 묶인 다른 hospital_id 들의 lab_results.value 중앙값' 으로 적었는데, 이 편은 다른 병원마다 중앙값을 먼저 내고 그 중앙값들의 중앙값을 쓰며 폐기·검체·단위로 이미 걸린 매핑은 뺍니다. 이유는 결과값을 한데 모으면 H11 의 77·81 두 값이 기준을 약 39 로 끌어올려, 정상인 H01·H02·H04 크레아티닌 매핑 셋이 다른 병원과 값 범위가 어긋남으로 뒤집히기 때문입니다. [판정 차례 · 규칙이 둘 이상 걸릴 때] 표준용어 담당자가 병원에 보낼 요청은 매핑마다 한 가지라, 아래 차례에서 처음 걸린 사유만 표에 띄웁니다. ① 폐기된 LOINC 코드에 매핑됨 → ② 검체가 LOINC 와 다름 → ③ 결과 단위가 LOINC 와 안 맞음 → ④ 다른 병원과 값 범위가 어긋남 → ⑤ 매핑 그대로 사용. 쓸 수 없는 코드는 나머지를 견줄 까닭이 없고, 검체가 다르면 단위가 맞아도 다른 검사입니다. 값 범위는 단위 칸이 맞아 보여도 숫자가 어긋난 매핑을 잡는 마지막 단계입니다. [하드 케이스 · 판정이 갈리는 이유] MAP-H07-0012 는 단위 mmol/L 로 먼저 걸려 값 범위 배수 16.75 가 있어도 단위 판정입니다. MAP-H03-0008 은 단위 mg/dL 도 2885-2 와 다르지만 검체가 앞이라 검체 판정입니다. MAP-H11-0041 은 단위 칸이 mg/dL 로 맞아 값 범위에서만 걸립니다. MAP-H04-0015 의 mg/dl 은 대소문자만 다른 같은 단위라 걸리지 않습니다. MAP-H08-0007 은 다른 병원 중앙값 15 와 3.67배 차이라 5배 기준 안쪽에서 그대로 사용이고, 기준을 3배로 잘못 잡으면 값 범위로 넘어갑니다. MAP-H09-0006 은 specimen 이 null 이라 검체 비교를 건너뛰고, 같은 코드를 쓰는 다른 병원이 없어 other_median 이 null 입니다. LR-0202 는 value 가 null 이라 H02 중앙값에서 빠집니다. MAP-H14-0002 의 2951-8 은 용어표에 없어 폐기 판정으로 갑니다. [평가 러너 · 2주차] 더미 매핑 300건에 LOINC 정의를 읽고 먼저 붙여 둔 판정과 자동 판정을 견줘 다른 매핑 수를 세고, 월별 재적재 뒤에도 같은 파일이면 판정이 바뀌지 않는지 봅니다. [수동 검증 · 사람이 봅니다] 1. 값 범위로 걸린 매핑이 단위 환산 누락인지 환자군 차이인지는 참여 병원 담당자가 값 분포를 보고 정합니다. 2. 3주차 후보 코드 가운데 어느 것으로 바꿀지는 표준용어 담당자가 고릅니다.