문제: 사고 시점의 기상은 위험 신호인가
해양사고 기록(MTIS)과 해양기상 관측(NMPNT)을 결합해 “어떤 기상 조건이 사고 위험을 높이는가”를 검증하고 싶었습니다. 가장 쉬운 방법은 사고가 난 시각의 기상과 안 난 시각의 기상을 단순 비교하는 것인데, 이 비교는 시작하기 전에 이미 오염되어 있습니다.
사고는 배가 바다에 나가 있어야 일어납니다. 그런데 출항과 조업은 아무 때나 일어나지 않습니다. 조업이 몰리는 시간대, 성수기인 계절, 주말과 평일의 차이 같은 요인이 기상과 사고 양쪽에 동시에 영향을 줍니다. 여름 낮에는 조업도 많고 기온도 높습니다. 이때 “기온이 높을수록 사고가 많다”는 상관이 관측되더라도, 그것이 기온의 효과인지 조업량의 효과인지 단순 비교로는 구분할 수 없습니다. 이런 제3의 변수를 교란(confounding)이라 부르고, 관찰 데이터 분석의 설계는 사실상 교란과의 싸움입니다.
설계 선택지: 무엇으로 교란을 통제할 것인가
이 질문에 쓸 수 있는 표준적인 역학 설계는 크게 세 갈래입니다.
코호트/케이스-컨트롤 — 개체 간 비교. 사고가 난 배와 나지 않은 배를 비교하는 방식입니다. 문제는 배마다 크기·항로·조업 습관·정비 상태가 다르고, 이 차이가 전부 잠재적 교란이라는 점입니다. 통제하려면 그 변수들을 측정해서 모델에 넣어야 하는데, 사고 통계에는 그런 정보가 대부분 없습니다.
case-crossover — 자기 자신과의 비교. 사고가 난 배의 사고 시각과 같은 배의 다른 시각을 비교합니다(Maclure가 1991년에 제안한 설계로, 대기오염과 심근경색처럼 “급성 노출 → 일시적 효과 → 이벤트성 결과” 구조에 널리 쓰입니다). 자기가 자기의 대조가 되므로, 시간에 따라 변하지 않는 특성(배·선장·항로·습관)은 측정하지 않아도 전부 통제됩니다. 기상처럼 시간 단위로 변하는 급성 노출의 효과를 보는 데 딱 맞는 구조입니다.
대조 시점을 고르는 방식이 다시 갈립니다. 사고 전 시점만 대조로 쓰는 단방향(unidirectional) 방식은 구현이 쉽지만, 노출에 계절 추세가 있으면 편향됩니다. 기온이 여름으로 갈수록 오르는 추세라면 “사고 전”은 체계적으로 더 서늘했던 시점이 되기 때문입니다. 그래서 시간층화(time-stratified) 방식을 따랐습니다. 사고 시각을 같은 달 · 같은 요일 · 같은 시각의 다른 날들과 한 묶음(stratum)으로 만드는 방식으로, 대조가 사고 앞뒤 양쪽에 대칭으로 배치되어 추세 편향이 상쇄되고, 요일·시각 효과는 묶음 정의 자체가 통제합니다(Lumley & Levy 2000; Janes et al. 2005).

이렇게 만든 분석 묶음이 사고 9,687건, 사고당 평균 대조 3.1건입니다.
추정: 조건부 로지스틱 회귀가 하는 일
묶음 데이터에는 일반 로지스틱 회귀를 쓸 수 없습니다. 묶음마다 고유한 절편(그 배·그 장소·그 계절의 기본 사고 성향)이 있는데, 묶음 수가 9,687개나 되므로 이걸 전부 파라미터로 추정하려 들면 추정이 무너집니다(sparse data에서의 incidental parameter 문제). 조건부 로지스틱 회귀는 묶음 안에서 “어느 시점이 사고 시각이었나”의 조건부 확률만 사용해 우도를 세우므로, 묶음별 절편이 수식에서 소거됩니다. 결과적으로 묶음 간 차이는 전혀 쓰지 않고 묶음 안의 대비만으로 기상 계수를 추정하게 됩니다. 자기 대조 설계의 논리가 추정식에 그대로 구현되는 셈입니다.
계수 해석을 쉽게 만들기 위해 기상 변수는 전체 표준편차로 나눠 표준화했습니다. 이러면 오즈비가 “그 변수 1표준편차 증가당 사고 오즈가 몇 배가 되나”로 읽히고, 단위가 다른 변수끼리(풍속 m/s와 기온 ℃) 크기 비교가 가능해집니다.
다중검정: 왜 BH 보정인가
풍속·기온·기압·습도 네 변수를 함께 검정하면, 효과가 전혀 없어도 5% 유의수준에서 우연히 유의한 변수가 나올 확률이 커집니다. 보정 방법은 크게 두 계열입니다. Bonferroni류는 “하나라도 거짓 양성이 나올 확률”(FWER)을 통제하는 대신 검정력이 크게 줄고, Benjamini–Hochberg(BH) 는 “유의 판정 중 거짓의 비율”(FDR)을 통제해 탐색적 분석에서 검정력을 덜 잃습니다. 이 분석은 가설을 확정하는 자리가 아니라 위험 신호 후보를 걸러내는 탐색적 성격이라 FDR 통제가 목적에 맞았고, p값을 BH로 보정한 q값 기준으로 판정했습니다.
결과: 직관과 반대
| 변수 | 오즈비 (1SD당) | 95% CI |
|---|---|---|
| 풍속(m/s) | 0.903 | 0.88–0.93 |
| 기온(℃) | 1.248 | 1.17–1.33 |
바람이 셀수록 사고 오즈가 줄어드는 방향이었습니다. “험한 날씨가 사고를 부른다”는 직관과 정반대입니다. 네 변수를 한 모델에 넣어 서로 보정한 다변량에서도 방향은 같았습니다(풍속 0.920 · 기온 1.290). 우연도 아니고(q값 기준 유의), 변수 간 교란도 아니라면, 남는 질문은 하나입니다. 이 연관은 무엇의 연관인가.
분해: 사고 유형을 나누면 그림이 달라진다
사고종류를 기상 민감형(충돌·좌초·전복·접촉·침몰·침수, 3,212건)과 기계·비기상형(기관손상·부유물감김·추진축계손상 등, 5,239건)으로 나눠 같은 분석을 반복했습니다.
| 변수 | 기상 민감형 | 기계·비기상형 |
|---|---|---|
| 풍속(m/s) | 1.025 (0.978–1.074) | 0.803 (0.771–0.836) |
| 기온(℃) | 1.031 (0.926–1.148) | 1.447 (1.330–1.575) |
강한 연관은 전부 기계·비기상형에 몰려 있었고, 정작 기상 민감형 사고에서는 풍속이 유의하지 않았습니다. 해석이 여기서 바뀝니다. 기관 고장 같은 사고는 험한 기상이 원인이라기보다, 출항과 조업이 늘어나는 잔잔하고 따뜻한 날에 더 많이 일어나는 것입니다. 사고 시점 기상과의 연관은 위험 신호가 아니라 노출(조업 활동)의 흔적이었습니다. 시간층화가 통제하는 것은 “같은 달·요일·시각”이라는 시간 구조까지이고, 그 안에서 날씨를 골라 나가는 행동(좋은 날 출항)은 남습니다. 설계가 통제하는 것과 남기는 것을 구분해야 결과를 바로 읽을 수 있습니다.
배운 것
- 설계가 결론을 만듭니다. 교란을 통제하지 않은 단순 비교였다면 “따뜻하고 잔잔한 날이 위험하다”는 이상한 결론을 그대로 믿었을 겁니다. 자기 대조 설계는 측정 못 한 교란까지 지워 주는 대신, 무엇이 지워지고 무엇이 남는지를 정확히 알아야 합니다.
- 전체 평균은 자주 거짓말을 합니다. 유형 분해 후에야 “기상 연관의 대부분이 노출 효과”라는 해석이 가능해졌습니다. 유의한 오즈비가 나왔다는 사실보다, 그것이 어느 부분집단에서 오는지가 해석의 본체였습니다.
- 예측 모델의 피처 중요도를 “위험 요인”으로 읽으면 안 되는 근거가 생겼습니다. 모델이 학습하는 것은 위험이 아니라 위험과 노출이 섞인 패턴입니다. 격자×시간 위험도 모델(같은 저장소의 LightGBM)의 기상 피처 중요도를 인과로 해석하지 않기로 한 결정은 이 분석에서 나왔습니다.
수치 출처는 저장소의 reports/stats/case_crossover.md이고, scripts/run_stats.py로 재현할 수 있습니다.