읽는 법 — 배경지식 없이 처음 읽는다면 그림 중심의 쉬운 버전(5분)부터 보면 좋다. 바쁘면 위 다섯 줄과 §1~2만 읽어도 흐름이 잡힌다. §3은 예측을 만들고 검증한 방법, §4는 시스템이 돌아가는 구조, §5는 우리 스스로 찾은 결함과 그 처리, §6은 9/5 실전 결과와 채점이다. 낯선 용어는 모두 §7 용어 사전에 풀어 두었고, 차트는 점에 마우스를 올리면 값이 나온다.
서울세계불꽃축제는 매년 여의도 한강공원 일대에 약 100만 명이 모이는, 한화가 주최하는 국내 최대 규모 불꽃 행사다. 문제는 축제가 아니라 축제가 끝난 직후 1~2시간이다.
21시가 넘어 마지막 불꽃이 터지면, 공원에 있던 사람들이 한꺼번에 지하철역으로 걷기 시작한다. 이때 벌어지는 일:
공원에서 가장 가까운 역은 여의나루역(5호선)이다. 네이버지도·카카오맵에 "집 가는 길"을 검색하면 당연히 여의나루역으로 안내한다. 그런데 축제일 저녁 여의나루역은 안전상 무정차 통제된다. 걸어가 봐야 닫혀 있다.
이것은 추측이 아니라 실측이다. 서울교통공사 승하차 데이터(OA-12921)를 보면:
| 실측 (2024·2025 축제일) | 수치 | 의미 |
|---|---|---|
| 여의나루역 19~21시 하차 인원 | ≈ 0명 | 무정차 통제 — 역이 사실상 닫혀 있었다 |
| 여의도역 21시 승차 | 평시 토요일의 12~17배 | 통제를 피한 인파가 옆 역으로 몰렸다 |
| 축제일 저녁 7개 역 초과 승차 합 | 약 10.9만 명 (2년 평균) | 귀가 인파의 실제 규모 |
서울시 실시간 도시데이터라는 훌륭한 공공 API가 있고, 여의도 인구·혼잡도를 5분마다 알려준다. 하지만 알려주는 것은 "지금 붐빔"이라는 상태까지다. 관람객이 정작 알고 싶은 "그래서 어디로, 언제 나가야 하나"라는 행동을 알려주는 서비스는 없다.
KT 통신 데이터 기준 관람객 최다 집단은 20·30대 여성이다. 대부분 대중교통으로 귀가하고, 쇼가 끝난 뒤 어두운 공원에서 통신까지 폭주하는 상황에서 판단해야 한다. 그 순간에 복잡한 앱은 못 쓴다 — 한눈에 읽히는 한 장이 필요하다.
출구(지하철역 6개 + 도보 경로 1개)마다 시간대별로 "얼마나 막힐지"를 미리 예측해서, 순위·등급·예상 대기시간으로 보여주는 웹페이지다. 열면 3초 안에 답이 나온다.
ML로 풀려면 학습 데이터가 필요한데, 이 축제의 데이터는 2024·2025년 단 2일뿐이다. 표본 2개로 모델을 학습시키면 외우기(과적합)가 될 뿐이다. 그래서 학습 대신, 실측값을 뼈대로 쓰고 물리 법칙(걷는 속도, 역 처리량)으로 살을 붙이는 구조 모델을 택했다. 구조 모델은 규칙을 데이터에서 통째로 배우게 하는 대신, 규모(Est)·분배(비중)·시간 형태(도착 곡선)처럼 사람이 검증할 수 있는 부품으로 식을 조립하는 방식이다. 부품마다 따로 근거를 대고 따로 고칠 수 있어, 표본이 적어도 어디가 틀렸는지 짚을 수 있다. 미국 애틀랜타 지하철(MARTA)의 경기장 이벤트 수요 예측 논문도 같은 접근으로 오차 11.7%를 달성했다 — 데이터가 적을 땐 이 방식이 정석이다.
| 요소 | 무엇인가 | 어떻게 구했나 |
|---|---|---|
| Est 규모·분배 | 축제일에 각 출구로 나간 실제 인원. "초과 승차" = 축제일 승차 − 평시 토요일 중앙값(평소 그 역을 쓰는 사람을 뺀 순수 축제 인파) | 서울교통공사 시간대별 승하차 + 교통카드 일별 데이터, 2년 평균. 비중: 여의도(5) 29% · 샛강 17% · 여의도(9) 17% · 마포도보 13% · 국회 11% · 여의나루 10% · 신길 3% |
| 도착형태 시간 분포 | 인파가 몇 시에 역에 도착하는가 | KT 생활이동 유출 곡선을 쇼 종료 시각에 맞춰 이동(2026년은 21:10 종료라 과거보다 +40분) → 관람 구역에서 각 출구까지 거리 ÷ 보행속도로 지연. 보행속도는 밀도가 높을수록 느려지는 공학 공식(Weidmann) 사용 |
| α 당일 배율 | 오늘 인파가 예년 대비 몇 배인가 | 당일 실시간 관측으로 갱신 (3.4) |
위 곱셈식을 기호로 적으면 다음과 같다. 역 \(st\), 시각 \(h\)의 출구 수요는
\[ D_{st}(h) \;=\; \alpha \cdot E_{st} \cdot \varphi_{st}(h), \qquad \textstyle\sum_h \varphi_{st}(h) = 1 \]이고, 도착 형태 \(\varphi_{st}\)는 KT 유출 곡선을 쇼 종료 이동분만큼 옮긴 뒤 도달 지연으로 시간대에 배분한다:
\[ \varphi_{st}(h) \;=\; \sum_{k\in\{0,1,2\}} w_{st}(k)\,\hat g(h-k), \qquad \hat g(h) = g_{\mathrm{KT}}(h - \Delta_{2026}),\ \ \Delta_{2026} = +40\text{분} \]배분 비율 \(w_{st}\)는 도달 지연 \(\tau_{st}\)에서 나온다 — 시간대 안 균등 출발을 가정하면 \(\tau_{st}\)분 걸리는 이동은 같은/다음 시간대로 \((60-\tau)/60,\ \tau/60\)씩 갈린다. 지연 자체는 거리 나누기 밀도별 보행속도다:
\[ \tau_{st} = \frac{1}{60}\!\left[\frac{\ell_1}{v(\rho_{\mathrm{zone}})} + \frac{L_{st}-\ell_1}{v(\rho_{\mathrm{street}})}\right]\!, \qquad v(\rho) = \max\!\Big(0.15,\ 1.34\big[1-e^{-1.913(1/\rho-1/5.4)}\big]\Big)\ \mathrm{m/s} \]\(v(\rho)\)는 Weidmann(1993)의 Kladek 식(§8.2 [2]). \(L_{st}\) = 관람 구역→출구 직선거리 × 우회계수 1.3(추정 — 9/1 구축한 보행망으로 재현하면 이벤트광장→여의도역 1.31배로 이 값에 가깝다, §3.10), \(\ell_1 = \min(300\,\mathrm{m}, L_{st})\)은 관람 구역 밀도 \(\rho_{\mathrm{zone}}\)로 걷는 초반 구간(추정), 이후는 가로 밀도 \(\rho_{\mathrm{street}}=1.5\)명/m²(추정). \(\rho_{\mathrm{zone}}\)은 당일 CCTV 등급에서 읽고(여유 1.5 · 주의 3.0 · 경계 4.0 · 심각 5.0명/m², §3.7), 관측이 없으면 3.0. 구현: src/nowcast.py kladek()·lag_table().
| 기호 | 뜻 | 값 · 산출 | 근거 |
|---|---|---|---|
| \(D_{st}(h)\) | 역 \(st\)·시각 \(h\)의 출구 수요 | 본문 수요식 | — |
| \(\alpha\) | 당일 규모 배율 | 사전 1.0 · 당일 사후분포 p50 (§3.4) | 당일 관측 |
| \(E_{st}\) | 축제일 초과 승차 (연도별) | 표 3-2 | OA-12921 · OA-12914 |
| \(\varphi_{st}(h)\) | 도착 형태 (정규화) | KT 유출 곡선 × 도달 지연 배분 | OA-22300 |
| \(\Delta_{2026}\) | 쇼 종료 이동 | +40분 (20:30 → 21:10) | 공식 공지 |
| \(\tau_{st}\) | 도달 지연 | 거리 ÷ \(v(\rho)\) | Weidmann 1993 |
| \(v(\rho)\) | 밀도별 보행속도 | \(v_0\) 1.34 m/s · \(\rho_{\max}\) 5.4명/m² · \(\gamma\) 1.913 · 하한 0.15 | Weidmann 1993 |
| 우회계수 · \(\ell_1\) · \(\rho_{\mathrm{street}}\) | 경로 보정 상수 | 1.3 · 300 m · 1.5명/m² (2026-09-05 정정: 화면 경로 비용의 가로 기본은 0.8명/m², 여유 등급 0.5명/m² — §3.10) | 추정 |
| \(C_{st}\) | 처리 기록 최대 | 표 3-2 — 축제일 관측 최대 시간당 승차 (설계 용량 아님, 용량의 하한) | OA-12921 관측 |
| \(L_{st},\ Q_{st},\ W_{st}\) | 부하율 · 대기열 · 대기시간 | §3.3 보존식 | — |
| \(\sigma_{O1},\ \sigma_{O2}\) | 관측 오차 (상대) | 15% · 20% | 추정 |
| 역 | E 2024 | E 2025 | E 평균 | 비중 | Cst | 비고 |
|---|---|---|---|---|---|---|
| 여의도(5) | 38,281 | 25,159 | 31,720 | 29.1% | 17,788 | — |
| 샛강(9) | 19,019 | 18,268 | 18,644 | 17.1% | 8,455 | † |
| 여의도(9) | 18,444 | 17,787 | 18,116 | 16.6% | 13,208 | † |
| 마포역 도보 | 13,786 | 15,277 | 14,532 | 13.3% | 15,000 | † 보행로 |
| 국회의사당(9) | 9,322 | 14,410 | 11,866 | 10.9% | 7,373 | † |
| 여의나루(5) | 7,454 | 13,950 | 10,702 | 9.8% | 9,577 | 통제 20~21시 |
| 신길(1·5) | 2,412 | 4,477 | 3,444 | 3.2% | 5,546 | † 1호선 합산 |
| 합계 | 108,718 | 109,328 | 109,023 | 100% | — | 총량 차 0.6% |
E = 축제일 승차 − 평시 토요일 중앙값(그 해 전체), 19~23시 합. † = 용량 추정(9호선·1호선 합산·보행로 — OA-12921 밖). 역별 E는 해마다 흔들리지만(여의도(5) 3.8만 ↔ 2.5만) 합계는 0.6% 차로 안정적이다 — 규모 예측이 성립하는 근거이자, 단일값 대신 2년 범위 밴드를 쓰는 이유다(§3.5 히스토리 표). 산출: data/derived/exit_shares.json.
기호로 적으면 — 부하율, 시간대를 넘는 대기열, 대기시간은
\[ L_{st}(h) = \frac{D_{st}(h)}{C_{st}}, \qquad Q_{st}(h) = \max\big(0,\ Q_{st}(h\!-\!1) + D_{st}(h) - C_{st}\big), \qquad W_{st}(h) = 60\,\frac{Q_{st}(h)}{C_{st}}\ \text{분} \]\(Q\)는 유량 보존식이고 \(W\)는 Little 법칙(대기열 ÷ 처리율)이다 — 자유 파라미터가 없어, 수요와 용량이 맞으면 자동으로 맞는다. 통제 이월은 여의나루 \(h\in\{20,21\}\)에서 \(D=0\)으로 두고 그 도착분을 해제 후 첫 시간대(22시)에 가산하는 규칙이다. 이것은 안전측 근사다 — 공지상 통제는 20:40~21:40(60분)이라 20:00~20:40과 21:40~22:00은 열려 있지만, 2024·2025 실적은 두 해 다 19시부터 하차가 0이어서 현장이 공지보다 일찍 무정차로 전환했다. 열려 있다고 가정했다가 조기 무정차가 나면 승객이 탈 수 없는 역에서 대기하게 되므로, 모델은 두 시간을 통째로 닫고 화면 문구만 "공지 기준 20:40부터 · 예년엔 조기 무정차"로 조건부로 안내한다(2026-09-01 자체 검증 H2). 보존 검증은 상시 테스트(tests/test_model.py), 대기 분의 실측 대조는 9/5 현장 스톱워치로 하려 했으나 실측이 없어 미검증으로 남는다(§6.2).
α 추정은 격자 베이즈 갱신이다. 로그 등간격 61점 \(\alpha \in [1/3, 3]\) 위에서
\[ w(\alpha) \;\propto\; p_0(\alpha) \prod_{i=1}^{n} \mathcal{N}\big(y_i;\ A_i\,\alpha + B_i,\ \sigma_i\big), \qquad p_0 = \mathrm{LogNormal}(0,\ 0.25) \]를 계산하고 \(\hat\alpha = p50\), 예측 밴드는 \([p10, p90]\)을 쓴다. 사전분포 폭 0.25는 p10/p90이 0.73/1.38로 2년 관측 밴드와 맞도록 정했다. 관측 \(y_i\)는 두 채널이다:
| 채널 | 관측 \(y\) | 예측항 \(A\alpha + B\) | \(\sigma\) | 시간 창 |
|---|---|---|---|---|
| O1 도착측 | 여의나루 30분 하차 증분 | \(A\) = 2년 평균 증분, \(B = 0\) | 15% | ~19시 (기준 증분 < 200 창은 제외) |
| O2 귀가측 | 핫스팟 9역 합산 30분 승차 | \(A = c \cdot\) 초과(α=1)/2, \(B = c \cdot\) 평시/2 | 20% | 19시~ (\(c\) = 커버리지 추정) |
구현: src/nowcast.py assimilate(). 사후분포가 격자 끝에 붙으면(edge_hit) 관측과 사전이 크게 어긋난다는 경고로 기록한다.
커버리지 \(c\)(핫스팟 9역 ÷ 우리 6출구)는 당일 14~17시 30분 창의 중앙값으로 추정한다. \(\alpha\)는 \(c\)에 반비례하므로 이 값 하나가 규모 전체를 흔든다 — 창이 3개 미만이거나 창끼리 (최대−최소)÷중앙값이 0.3을 넘으면 추정을 버리고 고정값 1.3을 쓴다. 실제 사용값·산포는 assimilation.coverage_basis·coverage_spread로 발행 데이터에 남긴다(2026-09-01 자체 검증 H5).
redteam-20260901.md §C1.
예측 모델은 "맞는지"를 반드시 숫자로 확인해야 한다. 방법: 한 해의 데이터를 가리고, 다른 해의 데이터만으로 그 해를 예측한 뒤 실측과 비교한다. B 모드가 2026년 예측이 실제로 놓이는 조건과 같다(과거 데이터만 있음).
| 모드 | 2024 오차 | 2025 오차 | 등급 적중률 | 뜻 |
|---|---|---|---|---|
| A: 그 해 데이터로 그 해 재현 | 0.24 | 0.21 | 82% / 100% | 시간 분배 로직 검증 |
| B: 다른 해 데이터로 예측 | 0.42 | 0.44 | 76% / 88% | 2026 조건의 실전 오차 |
오차 = |예측−실측| 합 ÷ 실측 합 (시간대 승차가 있는 4개 역 기준). B 오차의 주범은 해마다 총 인파가 다르다는 것(여의도(5) 21시: 2024년 17.8천 ↔ 2025년 12.5천) — 이 폭을 예측 밴드로 정직하게 표시한다. 등급 적중률이 더 중요하다: 관람객이 실제로 보는 것은 숫자가 아니라 여유~심각 등급이고, 이건 B에서도 76~88% 맞는다. 이 밖에 코드가 바뀔 때마다 자동으로 도는 회귀 테스트 122건(2026-09-08 기준 — 수요 총량 보존·통제 이월·쇼 종료 입력 방어·발행 스키마·혼잡장 수치 등)이 상시 통과 상태다. 8/31에는 22건이었고, 9/1 자체 검증(§5)의 조치를 실패하는 테스트부터 쓰는 방식으로 넣으면서 45건이 됐다.
오차 지표는 시간대 절대오차 합 대 실측 합의 비다:
\[ \mathrm{err} = \frac{\sum_h \big|\hat D(h) - D_{\mathrm{obs}}(h)\big|}{\sum_h D_{\mathrm{obs}}(h)} \]| 역 | A: 2024→2024 | A: 2025→2025 | B: 2025→2024 | B: 2024→2025 |
|---|---|---|---|---|
| 여의도(5) | 0.17 (3/5) | 0.12 (5/5) | 0.38 (2/5) | 0.44 (4/5) |
| 여의나루(5) | 0.32 (1/2) | 0.18 (2/2) | 0.44 (1/2) | 0.54 (1/2) |
| 신길(1·5) | 0.26 (5/5) | 0.30 (5/5) | 0.69 (5/5) | 0.51 (5/5) |
| 마포역 도보 | 0.38 (5/5) | 0.38 (5/5) | 0.47 (5/5) | 0.30 (5/5) |
| 전체 | 0.245 (14/17) | 0.214 (17/17) | 0.420 (13/17) | 0.438 (15/17) |
읽는 법 — "2025→2024"는 2025년 데이터만으로 2024년을 예측한 교차 검증. 신길의 B 오차 0.69는 절대 규모가 작아(시간당 수백 명) 비율이 과장된 것으로, 등급은 5/5 전부 맞다. 여의나루 등급 분모가 2인 것은 통제로 열린 시간대가 두 개뿐이기 때문이다. 시간대별 원자료: data/derived/backtest.json.
축제는 2000년부터 열렸는데 우리는 두 해만 썼다. 지하철 승하차(OA-12921)는 2008년부터 연도별 파일이 있고, KT 생활이동 일별 OD 는 2023-01-01 부터 있다. 그래서 2023 은 소스와 목표 양쪽에, 2022 는 유출 곡선이 없어 목표(실측)에만 더했다(2020·2021 은 코로나로 열리지 않았다). 소스 3해 × 목표 4해에서 같은 해를 뺀 9쌍이다. 여의나루 통제 시간대는 축제일 승차 실측에서 읽었다 — 2022 는 20시 한 시간대(부분 통제), 2023 은 19·20시.
| 목표(실측) | 소스(E·곡선) | 승차 오차 | 초과 오차 | 등급 적중 |
|---|---|---|---|---|
| 2022 | 2023 | 0.45 | 0.53 | 15/19 (79%) |
| 2022 | 2024 | 0.34 | 0.40 | 16/19 (84%) |
| 2022 | 2025 | 0.53 | 0.62 | 15/19 (79%) |
| 2023 | 2024 | 0.32 | 0.37 | 16/18 (89%) |
| 2023 | 2025 | 0.38 | 0.43 | 14/18 (78%) |
| 2024 | 2023 | 0.35 | 0.40 | 13/17 (76%) |
| 2024 | 2025 | 0.42 | 0.47 | 13/17 (76%) |
| 2025 | 2023 | 0.22 | 0.25 | 17/17 (100%) |
| 2025 | 2024 | 0.44 | 0.49 | 15/17 (88%) |
| 9쌍 요약 | 평균 0.38 · 0.22~0.53 | 평균 0.44 · 0.25~0.62 | 134/161 (83%) |
승차 오차 = Σ|예측 승차−실측 승차| / Σ실측 승차, 초과 오차는 평시를 뺀 초과분 기준. 4역(여의도·여의나루·신길·마포) 19~23시. 원자료 data/derived/backtest_4y.json, 계산 tools/backtest_4y.py.
결론은 둘이다. 첫째, 표본을 2쌍에서 9쌍으로 늘려도 오차는 줄지 않았다 — 위 표 3-4 의 42~44% 는 두 해의 우연이 아니라 연도 간 이전 오차의 실제 크기다. 둘째, 이 값이 C1 이 요구하는 밴드의 바닥이다. α 사후 밴드가 관측을 먹고 ±5% 로 좁아져도 화면 밴드가 이 아래로 내려갈 근거가 없다. 이 검증은 보고서용이고, 9/5 에 도는 모델과 사전 예측표는 손대지 않았다.
share_mean 기준)| 구분 | 출구 | 수요 비중 | 왜 |
|---|---|---|---|
| 검증됨 | 여의도(5) · 여의나루(5) · 신길(1·5) · 마포역 도보 | 55.4% | OA-12921에 시간대 승차가 있어 시간대별 대조가 된다 |
| 미검증 | 여의도(9) 16.6 · 샛강(9) 17.1 · 국회의사당(9) 10.9 | 44.6% | 9호선은 OA-12921에 없다. 교통카드 일별 승차(OA-12914) 비례로 규모와 용량을 추정했을 뿐, 시간대 대조는 못 했다 |
약점을 먼저 말한다 (2026-09-01 자체 검증 H1·H3 · 부하율은 2026-09-03 정정본). 백테스트는 수요의 55.4%만 검증했고, 미검증 44.6%에 최악 후보가 몰려 있다. 사전 예측표 22시 부하율 상위는 여의나루 1.00 · 샛강 0.82 · 여의도(5) 0.66 · 국회의사당 0.65인데 2위와 4위가 검증 밖이고, 그 용량은 전부 추정값(estimated_capacity: true)이다. "샛강이 두 번째로 위험하다"는 결론의 근거는 9호선 실측이 아니라 교통카드 일별 비례 추정이라는 뜻이다. 9/5에도 9호선 역 단위 승차 관측은 없다(서울시 실시간 도시데이터의 승차는 핫스팟 합산이다) — 이 구간의 검증 재료는 CCTV 밀도와 현장 관찰뿐이다. 또 하나, 19시 여의나루는 2024·2025 두 해 모두 통제(하차 0)였는데 2026 모델은 공지(20:40~)를 따라 19시를 개방으로 둔다(부하율 0.18). 20·21시는 실제보다 보수적으로 닫으면서 19시는 이력보다 낙관적으로 여는 비대칭이다. 백테스트가 한 번도 검증하지 못한 시간대이므로 화면 문구는 "공지 기준"임을 같이 적는다.
그림 4 — 백테스트: 모델 곡선이 실측을 따라가는가. 대표로 여의도(5)역 저녁. 21시 정점의 높이·위치가 맞는다.
| 확인한 사실 | 수치 | 모델에 어떻게 반영했나 |
|---|---|---|
| 여의나루역은 저녁에 실제로 닫힌다 | 19~21시 하차 ≈ 0명 (2년 공통) | 통제 규칙 · "무정차" 표시 |
| 귀가 인파의 총 규모는 해가 바뀌어도 안정적 | 초과 승차 합 2024년 108,718 vs 2025년 109,328 — 차이 0.6% | 예측 가능성의 핵심 근거. 2년 평균을 규모의 기준점으로 |
| 단, 시간대별 배분은 해마다 다르다 | 여의도(5) 21시: 2024년 17.8천 ↔ 2025년 12.5천 | 단일값 대신 예측 밴드로 표시 |
| 샛강·마포 방면이 생각보다 크다 | 샛강역 축제일 승차 평시 6배 · 마포역 20~23시 10배(1.4만~1.6만 vs 평시 1.45천) | 수기 배정표 폐기 → 관측 비중 채택 (오차 0.34→0.24) |
| 여의나루 통제가 풀리면 몰아서 탄다 | 해제 직후 시간대 승차 2024년 2.3천 · 2025년 5.8천 | 통제 중 도착분을 22시로 이월 → "22시 여의나루 최악" 결론 |
| 다리 건너 걷는 조기 귀가가 있다 | 마포역 20시 실측 5.1천~5.8천 vs 모델 2.5천 | 알려진 한계로 문서화 (과소 예측 방향 명시) |
| 출발지 구성은 2년간 거의 동일 | 구성비 차 ±0.3%p · 올 때≈갈 때 대칭 ±6%p | 출발지 지도를 귀가 방향 예측에 재사용 |
| 피더 승차가 도착을 1시간 선행 | 상관 lag0 0.72 / lag1 0.99 (2년 공통) | 당일 조기 신호 후보 (9/6 분 단위 검증 후) |
| 대조 기준일도 검증해야 한다 | 2025 직전 토요일(10/4)이 추석 연휴 — 평시가 아님 | 하루 대신 연간 토요일 중앙값으로 교정 (과정 기록) |
그림 1 — 상위 피더 12곳 점·선 도식. 가운데가 여의도. 선 방향은 실제 방위, 중심에서 떨어진 거리는 지하철 소요시간(점선 링 = 10·20·30분, 추정), 원 크기는 2년간 여의도행으로 집계(귀속)된 인원. ▶ 재생을 누르면 낮 12시부터 인파 유입이 흐른다 — 유입 속도는 그 시각의 실측 승차 강도를 역별 비중으로 배분한 값(추정).
그림 2 — 핵심 근거: 시간이 맞물린다. 피더역들의 초과 승차(주황 실선)가 먼저 움직이고, 여의도 도착(파랑 점선)이 약 1시간 뒤를 그대로 따라간다. 상관계수 0.99. 차트 아래 슬라이더로 시각을 옮기면 같은 무리가 한 시간 뒤 도착하는 짝이 커서로 보인다.
그림 3 — 개별 역에서 보면. 영등포시장역(5호선, 여의도 3분)의 축제일 승차는 입장 시간대(12~17시)에만 평시보다 많고, 저녁이 되면 격차가 사라진다. "축제 가려고 탄 사람들"이라는 해석과 정확히 맞는 모양.
| 근거 | 내용 |
|---|---|
| ① 시간이 맞물림 | 피더 초과 승차 정점(17시) → 여의도 도착 정점(17~18시). 상관 0.99 (2024·2025 공통). 멀리 있는 역(성수 35분·잠실 30분)일수록 지연이 커진다 — 지하철 소요시간과 일치하는 물리적 패턴 (그림 2) |
| ② 2년 재현 | 같은 역들이 두 해 연속 같은 모양으로 초과. 일회성 요인이면 재현되지 않는다 |
| ③ 독립 소스 정합 | 역 승차(교통공사)와 휴대전화 이동(KT)이라는 서로 다른 두 데이터가 출발지 구성에서 맞물린다. 배분은 KT 구 총량을 상한으로 |
| ④ 오후에만 초과 | 초과분이 축제 입장 시간대(12~17시)에 몰리고 저녁엔 소멸 (그림 3). 통근·일상 수요라면 이런 모양이 안 나온다 |
| ⑤ 방향 대칭 | 올 때 출발지 구성 ≈ 갈 때 도착지 구성 (구 단위 차이 ±6%p 이내, KT 실측) — 그래서 이 출발지 지도를 귀가 방향 예측에 재사용할 수 있다 |
| 피더역 | 노선 | 귀속 인원(2년) | 같은 시각 r | 1시간 선행 r | 소요(추정) | 판정 |
|---|---|---|---|---|---|---|
| 영등포시장 | 5 | 3,432 | 0.86 | 0.74 | 3분 | 근거리 — 같은 시각 동행 |
| 홍대입구 | 2 | 3,537 | 0.82 | 0.81 | 15분 | 근거리 — 같은 시각 동행 |
| 신길 | 5 | 2,710 | 0.81 | 0.74 | 3분 | 근거리 — 같은 시각 동행 |
| 영등포구청 | 2·5 | 3,774 | 0.80 | 0.40 | 5분 | 근거리 — 같은 시각 동행 |
| 화곡 | 5 | 4,365 | 0.63 | 0.59 | 14분 | 중거리 — 두 위상 비슷 |
| 성수 | 2 | 3,339 | 0.64 | 0.95 | 35분 | 원거리 — 1시간 선행 |
| 낙성대 | 2 | 4,864 | 0.66 | 0.77 | 25분 | 원거리 — 1시간 선행 |
| 잠실 | 2·8 | 2,850 | 0.46 | 0.71 | 30분 | 원거리 — 1시간 선행 |
| 고속터미널 | 3·7 | 4,769 | 0.24 | 0.65 | 12분 | 환승 대기로 선행 추정 |
| 목동 | 5 | 3,424 | 0.13 | 0.16 | 9분 | 신호 약함 — 감시만 |
| 사당 | 2·4 | 3,279 | 0.04 | 0.12 | 18분 | 신호 약함 — 감시만 |
| 김포공항 | 5 | 3,484 | −0.19 | 0.30 | 25분 | 공항 유동 혼입 — 제외 |
2년 합동 Pearson, 표본 n=20 (2년 × 10시간대). 굵은 값이 그 역의 우세 위상. 근거리 4곳은 같은 시각(0.80~0.86), 원거리 3곳은 1시간 선행(0.71~0.95)이 우세하다 — 소요시간이 길수록 선행이 커지는 순서가 그대로 재현된다(근거 ①의 역별 분해). 다만 개별 역은 표본이 작아 잡음이 크므로, 본 판단은 12곳 합산 상관(lag1 0.99)으로 하고 이 표는 위상 확인과 당일 감시 우선순위(강한 역 위주)에 쓴다. 산출: data/derived/feeder_leadlag.json.
한계도 정직하게. 초과 승차가 전부 축제 인파는 아니다 — 서울 전 역의 초과 합은 여의도 유입 규모의 1.7~3.3배로, 다른 나들이·행사가 섞여 있다. 그래서 2년 연속 필터·구 총량 상한으로 보수적으로 배분(귀속)했고, 개별 역 중엔 잡음이 큰 곳도 있다(위 표: 사당 0.04 · 목동 0.13 · 김포공항 −0.19). 분 단위 정밀 검증은 9/5 라이브 수집으로 한다.
hls_hd)을 우선 읽고 실패하면 표준화질로 내려간다(2026-09-01 추가).confidence)와 플래그(저조도·배경차분 실패·밀도 포화)를 같이 남긴다. 발행 데이터에도 density·calibrated·confidence·flags가 실리고, 화면의 혼잡장이 이 값으로 관측 노이즈를 정한다(§3.9). 즉 미심쩍은 판독은 버리지 않고 "덜 믿는다".모델의 뼈대인 "규모"가 지하철 데이터 안에서만 맞는 것일 수 있다. 그래서 지하철과 독립인 제3의 소스(서울 생활인구, OA-14991 — 통신 기반 추계)로 같은 그림이 나오는지 확인했다.
| 연도 | 평시 토요일 (월내 중앙값) | 축제 당일 | 배수 |
|---|---|---|---|
| 2024 | 87,764 | 393,403 | 4.48 |
| 2025 | 81,456 | 359,281 | 4.41 |
당일 피크(19시)가 2년 연속 같은 배수로 재현되고, 시간 곡선의 모양도 모델의 유출 곡선과 맞물린다. 지하철 승하차(교통공사) · 이동 OD(KT) · 생활인구(추계)라는 서로 독립인 세 소스가 규모에서 합의한다 — §3.6 근거 ③과 같은 삼각측량이다.
| 연도 | 전야제 | 평시 금 중앙값 (51주) | 배수 | 참고: 여의도역 |
|---|---|---|---|---|
| 2024 | 8,510 | 4,521 | 1.88 | 0.94 |
| 2025 | 7,254 | 3,892 | 1.86 | 1.08 |
전야제 인파는 여의나루 하차 기준 평시 금요일의 1.9배 수준에서 2년 연속 재현되고, 여의도역은 평시 수준에 머문다. 이 수치를 9/4 전야 관측의 정상 신호 기준으로 삼았다 — 그날 관측이 이 규모면 파이프라인이 맞게 돌고 있는 것이다. (2026-09-06 정정) 9/4 전야 관측으로는 이 기준을 판정하지 못했다 — 판정 불가로 기록한다. 파이프라인 정상 여부는 대신 발행 주기·재기동 0·α 갱신으로 확인했다(§6.3). 한편 생활인구는 전야제를 동 단위에서 1.00~1.09배로만 본다 — 여의동의 평일 직장 인구에 희석되기 때문이다. 작은 행사는 역 단위 관측이 동 단위 추계보다 민감하다는, 우리 관측 설계(§3.4 O1·O2)의 방증이다.
산출: data/derived/lifepop_yeouido.json · data/derived/eve_rehearsal.json.
지점 \(x\)의 혼잡 지수 \(C(x)\in[0,1]\)를 관측 \(y_i = C(x_i) + \varepsilon_i,\ \varepsilon_i\sim\mathcal N(0,\sigma_i^2)\)에서 복원한다. 사후 평균과 분산은 표준 식이다:
\[ \mu(x) = m_0 + \mathbf{k}(x)^{\!\top}(\mathbf K + \boldsymbol\Sigma)^{-1}(\mathbf y - m_0), \qquad s^2(x) = k(x,x) - \mathbf{k}(x)^{\!\top}(\mathbf K + \boldsymbol\Sigma)^{-1}\mathbf{k}(x) \]커널은 두 길이척도의 Matérn 3/2 합이다 — 카메라 시야 규모(150m)와 구역 규모(1,200m)를 따로 잡는다:
\[ k(r) = \sum_{\ell\in\{150,\,1200\}} v_\ell\,(1+a_\ell)\,e^{-a_\ell}, \qquad a_\ell = \frac{\sqrt3\, r}{\ell}, \qquad v_{150}=v_{1200}=0.125 \]RBF(가우시안) 커널은 무한 번 미분 가능해 인파의 장으로는 지나치게 매끄럽다. Matérn 3/2는 한 번 미분 가능한 거친 면을 허용한다(Rasmussen & Williams 2006, §8.2 [6]). 길이척도 150m의 근거 후보: 관측 주기 5분 동안 밀도 3명/m²의 보행 이동 ≈ 99m(§3.2 속도식). 구현 docs/app/field.js · 커널 상수 docs/index.html APF_KERNEL.
| 관측 종류 | 기본 \(\sigma\) | 확대 규칙 (공통) |
|---|---|---|
| 밀도 보정 CCTV (현재 0대 — 2026-09-02 정정) | 0.10 | 신뢰도 낮음 ×2.5 · 플래그 하나당 ×1.3 · 경과 \(t\)분에 \(\sqrt{1+(t/15)^2}\)배(15분에 √2배, 2시간에 8배 — 오래된 관측은 스스로 사전으로 돌아간다) · 같은 관측을 \(n\)곳에 복제하면 ×√n(정보량을 1건으로 유지) |
| 구역 등급 (서울시 citydata, 여의도한강공원) | 0.20 | |
| 미보정 CCTV (23대, 판독 등급 여유·주의·경계·심각 → 0.3·0.7·0.9·1.0) | 0.30 |
2026-09-02 정정 — 밀도 보정 5대를 등급 판독으로 되돌렸다. ROI 면적(roi_m2 9,000~20,000m²)이 도로·교량 전체 면적이라
720×480 원거리 고각에서 군중 계수 모델이 셀 수 있는 규모와 두 자릿수 어긋났다. 「주의」(3명/m²)에 닿으려면 판독 인원 27,000~60,000 이 필요한데
8/29 야간 실측 최대는 8.4~29.3 이었다. 그대로 두면 이 5대가 언제나 「여유」를 가장 낮은 \(\sigma\) 로 주장해 혼잡장을 끌어내린다.
자체 점검에서 발견해 되돌렸고, 면적 산출 근거는 남겨 두어 근경 부분 ROI 로 재측정하면 복원된다.
사전 평균 \(m_0\)은 고정값이 아니라 관측 수준에서 잡는다(경험적 베이즈) — 관측마다 정보 가중치 \(w_i = k(0)/(k(0)+\sigma_i^2)\)를 주고, 기본값 0.3을 가짜 관측 3건만큼 섞어 가중평균한다. 고정 0.3이면 주변이 다 붐벼도 사후가 "여유"로 끌려간다 — 예컨대 미보정 카메라(σ 0.30)가 0.70을 봐도 사후는 0.59로 여유 밴드에 주저앉아 마커와 면이 어긋난다. \(w_i<0.10\)인 관측은 장에 사실상 반영되지 않고, 화면의 마커·배지도 같은 기준으로 "거의 반영 안 됨"을 표시한다. 격자는 200×156, 색은 \(\mu\), 불투명도는 확신도 \(1 - s/s_{\max}\)(\(s_{\max}=0.5\), 0.15에서 포화)다. 관측이 없는 곳은 색이 옅어질 뿐 회색으로 바뀌지 않는다 — 9/1 회색 혼합을 걷어낸 것은 화면 가독성을 위한 선택이고, "모르는 곳"이 색에서 사라져 낙관 쪽으로 읽힐 수 있다는 점은 인정한다(§3.11).
혼잡 지수는 밀도 5명/m²를 1로 두는 선형 사상 \(C = \min(1,\rho/5)\)이고, 서울시 4단계 등급은 여유 0 · 보통 ⅓ · 약간 붐빔 ⅔ · 붐빔 1로 놓았다. 이 사상과 길이척도·σ·가짜 관측 3건은 전부 가정이다. (2026-09-05 정정) 서울시 구역 등급 관측의 나이에서 API 발행 시차 28분(9/4~9/5 전 틱 실측, 28.8분 일정)을 뺀다 — 전엔 시차를 낡음으로 깎아 σ 가 1.1 로 불어 「붐빔」이 장에서 사실상 무시됐다. 같은 층을 관람객 화면에도 넣어 두 화면의 장이 같은 관측으로 만들어진다. 카메라가 있는 자리는 카메라(σ 0.3)가 이긴다. 9/5 관측이 쌓이면 관측 하나를 빼고 나머지로 그 자리를 맞히는 교차검증(LOO)으로 교체한다(다음 단계, §6.4). 거리가 유클리드라 한강 건너로 번지는 문제가 있고, 보행망 거리 커널이 답이지만 다음 단계 과제다. 검증은 tests/field_spec.mjs가 배포 중인 field.js를 node로 그대로 읽어 22개 단언(커널 단조성·Cholesky 재구성·σ 순서·경험적 베이즈 사전)을 확인한다 — 그래서 field.js는 DOM을 만지지 않는 순수 함수로 유지한다. \(\mathbf K+\boldsymbol\Sigma\)가 양의 정부호가 아니면 지터를 키워 6회 재시도하고, 그래도 안 되면 사전으로 폴백하며 ok:false를 남긴다.
보행망은 OpenStreetMap에서 여의도 일대(카메라 23대를 감싸는 범위)의 도로 기하를 내려받아 만든 그래프다 — 노드 9,219 · 간선 26,042 · 총 연장 1,486km(방향별) · 파일 5.95MB(gzip 전송 775KB). 경로를 처음 누를 때만 내려받는다(지연 로드). 간선 비용은 길이에 혼잡 위험을 곱한 값이고, 위험은 간선 중점에서 읽은 혼잡장 평균 \(\mu\)다:
\[ c(e) = \frac{\max(0.1,\ m_e)}{v(\rho_{\mathrm{eff}})},\qquad \rho_{\mathrm{eff}} = \kappa\,\rho(\mu(x_e)) + (1-\kappa)\,\rho_{\mathrm{street}},\quad \kappa = \min\!\Big(1,\ \tfrac{1-\sigma(x_e)/\sigma_{\max}}{0.15}\Big) \](2026-09-04 변경) 전에는 \( c(e) = \max(0.1, m_e)\,(1 + 1.25\,\mu) \) 였다. 가중치 1.25는 출처가 없었고, 최소화 대상이 사람이 신경 쓰는 값도 아니었다. 더 나쁜 것은 경로는 벌점으로 고르면서 화면의 소요 시간은 67m/분 고정으로 따로 계산해 둘이 따로 놀았다는 점이다. 지금 비용은 그 간선을 걷는 데 걸리는 시간이다 — \(v\)는 §3.2와 같은 Kladek 속도식이고 \(\rho\)는 혼잡장 값을 등급 사다리(여유 1.5 · 주의 3.0 · 경계 4.0 · 심각 5.0명/m²)로 되돌린 밀도다. (같은 날 낮 정정) 밀도를 혼잡장 값 그대로 쓰지 않고 장의 확신도 \(\kappa\)(σ에서, §3.9)로 관측 밀도와 가로 기본 \(\rho_{\mathrm{street}}=1.5\)명/m²를 섞는다 — 본 곳은 본 대로, 못 본 곳은 보통 가로. 그대로 쓰면 GP 사전(0.3)과 σ 0.3 수축이 카메라 없는 이면도로까지 2.25명/m²로 읽어 어느 경로든 위험이 같아지고, 균일 배율은 최소경로를 바꾸지 않아 우회가 사라졌다. 경로를 고르는 비용과 화면의 소요 시간이 같은 식이다 — 잠깐 둘을 나눴더니(비용은 장 전체, 표시는 처음 300m) "더 돌게 하고 더 느리다고 말하는" 모순이 났다. 실측 확인(2026-09-04): 실제 관측(15대)에서 6개 목적지 중 2곳이 60여 m 돌고, 교량·광장 심각 배치에서는 4곳이 돈다 — 신길역 +1,278m에 22분 단축, 국회의사당역 +312m에 12분 단축. (2026-09-06 정정) 이 가정 배치의 분 수는 9/5 의 ÷1.4 정정(아래) 뒤 다시 계산해 이벤트광장→여의도역 최단거리 45분 vs 혼잡 회피 21분이 됐다(docs/deck/route_demo.json). 9/5 실측 — M14 부분 닫힘. 9/4 실데이터에서는 장이 매끈해 경로가 바뀌지 않았지만(대장 M14), 9/5 발행 스냅샷 6개로 같은 계산을 다시 돌리면(tools/route_real.mjs) 6시각 × 목적지 6곳 = 36건 중 11건에서 최단시간 경로가 최단거리 경로와 달랐다. 쇼 종료 직후 21:31·21:36 에 4/6(여의도역 +196m·4분 단축 · 샛강 +239m·4분 · 신길 +69m·12분), 22:06 신길 +360m·12분, 23:02 신길 +87m·6분. 20:05 는 0/6 — 공원 전체가 붐빔이라 어느 길이나 같이 느렸다. 오늘 코드로 그날 관측을 다시 돌린 값이라 22:31 이전 화면이 실제로 그린 분 수와는 배율이 다르다(경로 선택은 배율에 거의 무관). 구현 docs/app/field.js blendSeconds(), 두 화면이 같이 쓴다. 속도식이 src/nowcast.py kladek()와 같은 값인지는 테스트가 대조한다(tests/test_routing.py).
탐색은 A*(이진 힙, 직선거리 휴리스틱)를 두 단계로 돈다. 1단계는 보행로·횡단보도·보행자 도로만 허용한 부분 그래프(출발·도착 180m 안에 같은 연결 성분이 있을 때), 2단계는 자동차전용·진입금지를 뺀 OSM 전체다. 화면에는 어느 단계로 찾았는지 표시한다. 브라우저 비용(맥 데스크톱, Node/V8): JSON 파싱 22ms · 그래프 구성 17ms · A* 5ms. 모바일은 몇 배로 본다.
도보 소요 시간은 §3.2와 같은 Kladek 속도식이다 — 처음 300m는 관람구역 밀도 3.0명/m², 이후 가로 1.5명/m². 경로탐색 모듈의 초기 구현은 상수 75m/분(1.25m/s)이어서 같은 1.47km 경로가 20분으로 나왔고, §3.2 기준으로는 39분이다(2026-09-03 정정 — 경로 길이를 1.82km 로 잡아 24분·47분으로 적었던 것을 재현값 1.47km 기준으로 고친다. 2배 차이라는 결론은 그대로다). 2배 차이는 원본이 축제 밤의 밀도를 넣지 않아서 생긴다. 관람객 화면(docs/go.html)은 그때 두 값 중 어느 쪽도 아닌 67m/분을 썼다 — 같은 경로가 22분으로 나왔다. (2026-09-04 결정) 두 화면 모두 위 \(c(e)\)의 구간별 시간을 그대로 표시한다. 같은 경로가 실제 관측(한산한 아침)에서 49분, 관측이 없으면 가로 기본(1.5명/m²)으로 30분이다. 세 값 사이의 선택은 이것으로 닫혔다. (2026-09-05 정정) 화면이 쓰는 밀도 사다리에서 여유 1.5 → 0.5명/m²(4.7km/h), 못 본 길의 가로 기본 1.5 → 0.8명/m²(4.2km/h)로 낮췄다. 1.5명/m² 는 Kladek 식으로 2.9km/h 라 한산한 새벽에도 같은 1.47km 가 32분으로 읽혔다 — 지금은 관측이 없으면 21분, 여유 관측이면 19분이다. 주의 이상은 그대로라 붐비면 여전히 느려진다. 모델의 도달 지연(§3.2, 첫 300m 3.0·이후 1.5)은 바꾸지 않았다 — 화면 시간과 모델 지연의 가로 밀도가 이제 다르다. 두 값 모두 가정이고 9/5 실측 뒤 다시 본다. (2026-09-05 22:30 정정, 당일) 걷는 시간 = Weidmann 시간 ÷ 1.4(속도 ×1.4, 자유보행 1.34 m/s 상한). Weidmann 식은 3.5명/m² 에서 0.8 km/h 까지 떨어지는데, 서울시 「붐빔」 배경 관측이 깔린 광장 일대(u≈0.8)에서 여의도역 1.4 km 가 72분으로 읽혔다 → 51분. 22:20 에 먼저 넣은 속도 바닥 2.2 km/h 는 주의·경계·심각의 시간 차를 지워 10분 만에 철회했다. 1.4 는 가정값이고 속도식 자체(§3.2, 모델 지연)는 그대로다. (2026-09-04 정정) 같은 날 관람객 화면을 v2 로 바꿨다. 경로는 두 화면이 같은 보행망 A* 와 같은 비용 \(c(e)\) 를 쓴다 — 관람객 화면은 첫 답을 늦추지 않으려고 보행망(5.9MB, 전송 0.8MB)을 첫 화면 뒤에 받고, 받기 전에는 역별 근사 경유점(직선합 ×1.15) 위에서 같은 속도식으로 시간만 세며 화면에 「근사」라고 적는다(같은 날 오전 한때 근사만 쓰기로 했다가, 근사 직선은 붐비는 곳을 돌아가지 못해 되돌렸다). 관람객 화면의 추천 1위는 부하율이 아니라 도보 + 대기 시간 오름차순이다(운영 화면·이 보고서의 순위는 부하율 그대로). 혼잡 가중 1.25는 출처 없는 추정치였다. (2026-09-03 정정) 이 보행망의 우회비는 이벤트광장→여의도역 직선 1,120m 대 경로 1,471m = 1.31배이고, 모델의 우회계수 1.3(§3.2)과 거의 같다. 초기 구현 문서(routing/README.md)가 적은 1,820m·1.64배는 지금 보행망에서 재현되지 않는다 — 마포대교 보완 간선과 태그 필터를 넣고 빼 본 네 조합이 모두 1,471m 였고, 같은 계산이 이벤트광장→마포역 1,907m(9/2 실측)는 정확히 재현한다. 따라서 "실측이 모델보다 크므로 보정이 필요하다"는 앞선 서술은 철회한다. 우회계수 1.3은 이 한 구간에서 잘 맞지만 표본이 하나뿐이라, 9/5 이후 여러 구간으로 다시 볼 항목으로 남긴다. 지도 데이터는 © OpenStreetMap contributors, ODbL. 구축·편입 기록: 저장소 routing/README.md.
맞는 답만큼 중요한 게 "왜 그 길로 안 갔나"다. 심사 항목("만든 과정")이기도 하다.
| 버린 것 | 왜 버렸나 | 대신 택한 것 |
|---|---|---|
| ML 학습 모델 | 학습 표본이 2일 — 외우기가 될 뿐 | 실측을 기준점 삼은 구조 모델 |
| 방향→역 수기 배정표 | 실측과 3~7배 어긋남 (샛강을 3.5배 적게 예측) | 관측 초과 승차 비중 — 백테스트 오차 0.34→0.24 |
| 평시 기준을 상위 10%로 | 환승 큰 역이 기준에서 밀려나는 왜곡 발견 | 토요일 중앙값 |
| 입자 필터(난수 시뮬레이션) | 추정할 값이 α 하나 — 난수가 필요 없음 | 결정론적 격자 (테스트 가능) |
| 피더 신호를 실전 모델에 직결 | 9/5 전에 분 단위 검증이 불가능 | 관측만 하고 사후 검증 → 확장 기능 |
| 가상 설문 1,000건 (생성 응답) | 실측(하차 0명 · 승차 12~17배)이 이미 있고, 생성 응답은 실측보다 근거 등급이 낮다 | 실측과 보도로 페인포인트 절 구성 — 8/31 드랍 |
| 관측마다 가우시안을 얹어 더하는 혼잡장 (반경 σ=220m, 초기 구현) | 신뢰도 낮은 관측을 버리거나 그대로 믿는 양자택일. 불확실성을 내놓지 못함 | 가우시안 과정 회귀 — 신뢰도를 노이즈 σ로, 불확실성을 불투명도로 (§3.9) |
| 불확실한 곳을 회색으로 섞어 그리기 | 화면이 탁해진다는 가독성 판단. 대신 낙관 편향 가능성을 §3.9에 명시 | 불투명도 + "관측 없음" 배지 + 한계 문구 (되돌리기는 1줄) |
| 스테일 CCTV 판독을 시간 기준으로 잘라내기 | 12시간 컷 안쪽의 3시간 전 판독이 "지금"으로 그려진다 | 경과 시간에 따라 σ 확대 — 사후가 저절로 사전으로 돌아간다 (§3.9) |
| 도보 소요 상수 75m/분 (초기 구현) | 축제 밤 밀도를 무시해 §3.2와 2배 어긋남 | 밀도별 속도식 → 구간별 걷는 시간 (§3.10 에서 닫음) |
핵심 설계 원칙: 아래층이 죽어도 위층이 산다. 라이브 수집이 전부 실패해도 사전 예측표가 있고, 인터넷이 끊겨도 기기에 저장된 마지막 화면이 있다.
도식 읽는 법: [사전층]의 산출물을 [당일층]이 보정하고, 그 결과를 [화면층]이 보여준다. 당일층이 멈추면 화면층은 사전층의 예측표를 그대로 쓴다.
[사전층] 행사 전에 완성 — 라이브 없이도 서비스 성립
data/raw (KT 이동·승하차·교통카드 원본)
├─ baseline.py ──────▶ 유출 곡선·역별 처리용량
├─ exit_shares.py ───▶ 출구별 실측 인파 E_st ← 모델의 뼈대
├─ line9_capacity.py ▶ 9호선 용량 추정
└─ backtrack.py ─────▶ 출발역 역추적 + 2026 사전 예측표
└─ backtest.py ─▶ 타임머신 검증 (§3.5 표)
[당일층] 9/4·9/5 — run_all.sh 가 프로세스 3개를 띄우고 워치독이 지킨다
① collector_api.py ── 도시데이터 5분 (여의도 3곳 상시 · 피더 12곳 12~19시)
+ 실시간 지하철 도착 17~23시 ──────────────┐
② collector_cctv.py ─ TOPIS 23대, 60초 (프레임 미저장 · 집계만) ─┼─▶ ③ nowcast.py ─▶ publish.py
쇼 종료 실시각 (현장 기입 · 형식·범위 검사) ─────────────────────┘ 5분 루프 · α 갱신·통제 이월·보행 지연
워치독 30초마다 생존 확인·재기동 · 수집 로그 10분 정체 경고 · 10분에 5회 넘게 죽으면 300초 간격
발행 내용이 같으면 커밋 안 함 · push 실패 시 pull --rebase 후 재시도, 충돌이면 abort + 경보
연속 실패 횟수는 data/live/publish_fail_streak ──▶ GitHub Pages
[화면층] 정적 웹페이지 (서버 없음) — 출구 랭킹 · 지도(혼잡장 + 회피 경로, MapLibre) · CCTV 카드
라이브 최신이면 "LIVE" · 15분 넘게 안 오면 "오래됨" · 아예 없으면 사전 예측표
+ 기기 저장(localStorage)으로 오프라인 폴백 · 지도 라이브러리·WebGL 실패 시 안내 문구로 폴백
당일층의 워치독·발행 방어·입력 검사는 9/1 자체 검증(§5, C2~C5)의 조치다. 9/2 저녁 30분 시험 운전이 이 조치들이 실제 수집기와 함께 도는 첫 실행이었고(고장 주입으로 워치독 재기동 1초 확인), 9/4 17:08 → 9/6 01:01 의 32시간 본번 운전에서 재기동 1회(계획된 간격 전환) · 크래시 0 · 슬립 공백 0 으로 지났다(§6.1).
| 소스 | 어디에 쓰나 | 비고 |
|---|---|---|
| KT 생활이동 OD (서울시 공개) | 인파의 시간 곡선·출발지 구성 | 축제일 2일 + 대조용 토요일 |
| 서울교통공사 시간대별 승하차 (OA-12921) | 출구별 실측 인파·용량·검증 | 1~8호선, 2개년 전체 |
| 교통카드 일별 승하차 (OA-12914) | 9호선 규모 (시간대 데이터가 없어 일별로) | 월 단위 파일 |
| 서울 실시간 도시데이터 (citydata) | 당일 α 관측·피더 감시 | 5분 주기, API 키 3개로 호출량 분산 |
| TOPIS 교통 CCTV | 보행 밀도 → 걷는 속도 보정 · 혼잡장 관측 | 23대(720p 9대), 등급 판독(밀도 보정은 9/2 보류), 프레임 미저장 |
| 2026 공식 공지 (주최측) | 통제 규칙·쇼 시간표 | 여의나루 20:40~21:40 등 |
| OSM 지도·교량 공식 제원 | CCTV 관심영역 면적 | 추정 표기 |
| OSM 보행망 (Overpass) | 혼잡 회피 경로탐색 그래프 | 노드 9,219 · 간선 26,042 · ODbL |
원칙: 모든 숫자에 출처·기준일을 남기고, 추정치는 "추정"으로 표기한다. 빈칸을 지어내지 않는다. 데이터셋 ID·링크·사용 범위는 §8에 상세히 정리했다.
| 시각 | 붐비는 곳 | 추천 |
|---|---|---|
| 21시 쇼 직후 | 샛강 0.66 주의 · 여의도(5) 0.58 주의 · 여의나루 통제 중 | 신길 0.16 여유 · 마포대교 도보 0.24 여유 |
| 22시 통제 해제 후 | 여의나루 1.00 [0.65~1.41] 심각 · 샛강 0.82 경계 | 신길 0.27 여유 · 마포대교 도보 0.38 여유 |
표의 숫자가 뜻하는 것 (2026-09-01 자체 검증 H4·M1 · 2026-09-03 수치 정정). 헤드라인 부하율은 2024·2025를 각각 계산해 평균한 값이다. 여의나루 22시 1.00은 2024년 0.72와 2025년 1.28의 평균이고, 화면의 대기 8분은 0분과 17분의 평균이다 — 부하율 1.00이면 대기가 사실상 0(0.2분)이어야 하므로 두 숫자는 어느 한 해의 상태가 아니다. 사실 그대로 말하면 "2년 중 1년은 용량을 28% 넘겼다"이고, 범위 [0.65~1.41]이 그 정보를 담는다. (2026-09-03 정정) 이 문단은 9/2까지 같은 자리를 0.91 [0.57~1.30]·대기 6분·"19% 초과"로 적었다. 부하율의 분자에 평시 토요일 승차가 빠져 있었기 때문이다(결함 H9) — 분모인 처리용량은 축제일 총 승차의 시간당 최댓값이라 분자도 평시 + 초과여야 단위가 맞는다. 고친 뒤 여의나루 22시는 경계에서 심각으로 올라갔고, 21시 여의도(9)·국회의사당은 0.50 동률이 됐다. 결론의 방향(여의나루 22시가 최악, 2년 중 1년은 용량 초과)은 그대로다. 또 하나의 한계: 순위는 선택한 시각의 부하율로만 매긴다. 21시 1·2위인 신길(도보 58분)·마포역 도보(43분)는 21시에 출발하면 22시에 닿는데 보여 주는 값은 21시 것이다. 도달 지연 \(\tau_{st}\)를 수요 배분에는 쓰면서 랭킹에는 아직 쓰지 않는다. "지금 출발 → 도착 시각 기준" 정렬은 다음 단계 개선안이다(§6.4).
(2026-09-06 실측 대조) 9/5 화면의 하루 최대 부하는 여의나루 22시 0.93(재개통 직후) · 샛강 0.85 였고 등급은 「경계」까지, 「심각」은 없었다. 사전표의 여의나루 22시 1.00 [0.65~1.41] 안에 들어온다. 실제 통제는 공지(20:40~21:40)가 아니라 18:10~22:05 였다 — 19시 통제를 당일 19:13 에 규칙에 추가했다(H3 확인, §6.1).
9/1, 실전 나흘 전에 공격자 관점으로 모델·파이프라인·대시보드를 깬 것을 시작으로, 실전 뒤까지 7회차 39건(치명 6 · 높음 10 · 중간 16 · 낮음 7, 철회 1)을 등재했다. 1~2회차는 코드를 읽었고, 4회차는 다른 모델(Codex)에게 전체 diff 를 주고 설계를 공격시켰으며, 3·5·6·7회차는 실행(시험 운전·야간 연속 운전·본번)에서 찾았다. 치명·높음은 전부 조치했고(C1 은 서술로 닫음), 중간·낮음의 보류 판단은 결함 대장에 근거와 함께 남겼다. 방법은 Claude Code에 "이 저장소를 깨라"는 공격 프롬프트를 주고, 모든 지적에 파일:줄 또는 데이터 파일로 재현 가능한 근거를 요구한 것이다.
공격이 통하지 않은 곳도 기록한다 — 같은 곳을 다시 파지 않기 위한 기록이다. API 키 유출(추적 파일·라이브 데이터·로그 전수 검색, 히트 0) · 오류 로그로 키가 새는지(가짜 키로 실제 호출, 예외 문자열에 키 없음) · HTML 이스케이프(API 유래 문자열 17곳 전부 적용) · 표 3-2·3-4·3-5·3-6 수치(원본 JSON에서 역산, 전부 일치) · KaTeX 렌더(3개 폭에서 DOM 계측, 에러 0·넘침 0) · 스테일·오프라인 폴백(3일 지난 데이터로 렌더, 사전 예측표로 정상 강등) · 지도 실패(라이브러리·WebGL 차단, 안내 문구 폴백).
| 회차 | 언제 · 방법 | 신규 | 무엇을 찾았나 · 처리 |
|---|---|---|---|
| 1 | 9/1 · 코드 읽기 | 18 | C1~C5 · H1~H5 · M1~M7 · L1 — 즉시 5건 + H2·H5 조치(TDD), 4건 보고서에 명시. 상세 표 5-1b |
| 2 | 9/2 · 미감사 파일(collector_cctv.py·field.js) | 8 | H6 CCTV 밀도 보정 스케일(면적이 두 자릿수 어긋나 보정 카메라 0대로 보류) · H7 α 기준선 시프트 누락 · M8 배경차분 일몰·정지 군중(부분) · M9·M10 조치 · L2~L4(자정 넘김·단위 테스트). H8(API 쿼터)은 철회 |
| 3 | 9/2 저녁 · 30분 시험 운전 + 고장 주입 | 2 | M11 관측 전 예측에 prior 표식 없음 · L5 Ctrl+C 뒤 정지까지 30초 — 당일 조치. L2·C3 닫힘(워치독 재기동 1초) |
| 4 | 9/2 밤 · Codex 교차검증(다른 모델이 전체 diff 공격) | 3 | H9 부하율 분자에 평시 승차 누락 → 여의나루 22시 경계→심각, 순위가 바뀜(§4.3) · H10 수집 끊김이 화면에 안 보임 → 표식·워치독·화면 3층 · M12 보류 |
| 5 | 9/3 · 테스트런(키 무효화로 끊김 재현) | 2 | H11 관람객 화면 지도 바닥이 신설 이후 안 그려짐(래스터 타일 404, 휴대폰으로 발견) · M13 우회비 1.64배가 재현 안 됨 → 1.31배로 정정, 보정 재료 서술 철회(§3.10) |
| 6 | 9/3~4 · 야간 연속 운전 | 3 | C6 뚜껑을 덮으면 맥이 자고 수집·워치독이 같이 멈춘다(caffeinate 무력) → 운전 절차에 반영 · L6 예약 종료 스크립트의 zsh 단어 분리 · M14 실측 장이 매끈해 경로가 안 바뀜 → 9/5 부분 닫힘(§3.10) |
| 7 | 9/5 · 본번 실전 | 3 | M15 유출 꼬리 과소(보류, §6.2) · M16 API 발행 시차 28.8분을 낡음으로 셈 → 당일 조치 · L7 자정 CCTV 빈 프레임 |
결함 대장은 저장소 redteam-20260901.md 하나이며 상태가 바뀌면 그 문서가 먼저다. 덱·보고서의 건수는 tools/deck_data.py 가 대장에서 세고 테스트가 대조한다.
| # | 등급 | 무엇이 깨지나 | 처리 |
|---|---|---|---|
| C1 | 치명 | α 사후분포 과신 — 관측 1건이 α를 1.0→0.53으로 끌고, 관측 20건이면 밴드가 ±5%로 붕괴(백테스트 오차는 ±42%). (2026-09-04 추가) 2022·2023 을 더한 4년 9쌍 교차 검증에서도 승차 오차 평균 38%(22~53%)·초과 44% — 표본 우연이 아니다(표 3-4b) | 서술로 닫음(9/6) — 밴드는 그대로, 실제 오차 하한 0.42~0.44 를 §3.4 상자에 못 박음. 본번 α 궤적은 표 6-2 |
| C2 | 치명 | 발행 실패를 아무도 모른다 — 내용이 같아도 시각만 바뀌어 매 틱 커밋, push 실패는 무시 | ✅ 내용 비교(generated 제외) · 실패 시 rebase 후 재시도 · 연속 실패 횟수 파일 + 경보 |
| C3 | 치명 | 수집기가 죽으면 재시작도 경보도 없다 | ✅ run_all.sh 워치독 — 30초 생존 확인·재기동 · 10분 정체 경고 · 시작 전 .env 키 점검 |
| C4 | 치명 | 쇼 종료 시각 기입 — 인자·파일·기본값 세 경로가 전부 취약하고 기입 절차 미정 | ✅ 형식·범위(19:00~24:00) 검사, 오류는 크래시 대신 사용법 출력 · planned_invalid_file 표기. 본번 21:27 기입으로 한 번 작동(§6.1) |
| C5 | 치명 | API 실패 원인이 로그에서 구분되지 않는다(키 만료·쿼터·장애가 같은 예외) | ✅ 비-JSON 응답 원문 200자를 예외에 · 로그 기록 전 키 값 제거 |
| H1 | 높음 | 백테스트가 수요의 55.4%만 검증 — 미검증 44.6%(9호선 3역)에 최악 후보 샛강·국회가 있다 | 보고서에 명시 — 표 3-4a로 승격 |
| H2 | 높음 | 통제창 20:40~21:40(60분)을 두 시간으로 반올림 | ✅ 안전측 근사임을 §3.3에 명시 · 화면 문구를 시간대별로 분기(20시 "공지 기준 · 예년엔 조기 무정차", 21시 "21:40 해제 예정") |
| H3 | 높음 | 19시 여의나루 — 2년 다 통제였는데 2026은 개방(0.18). 검증 근거 0에 낙관 | 보고서에 명시 — §3.5에 비대칭 명시 |
| H4 | 높음 | 사전 예측표가 연도 평균 — 부하율 1.00에 대기 8분이라는 자기모순 조합 (9/1 발견 당시 0.91·6분, 9/3 H9 정정 반영) | 보고서에 명시 — §4.3에 "2년 중 1년은 초과" 승격 |
| H5 | 높음 | 커버리지 c 하나가 α를 최대 3.75배 흔든다 · 문서(14~17시)와 코드(14~16시) 불일치 | ⚠️ 부분 — 창을 14~17시로 일치 · 산포 가드((최대−최소)÷중앙값 > 0.3이면 고정값) · coverage_spread 발행. 클램프 (0.8, 3.0)은 좁힐 근거가 없어 그대로 |
| M1 | 중간 | 순위가 부하율만 본다 — 도달 시간이 랭킹에 없다(21시 1위 신길은 도보 58분) | 보고서에 명시 — §4.3 한계 명시. 도착 시각 기준 정렬은 다음 단계 |
| M2 | 중간 | 데이터가 비면 어느 출구든 "여의나루 통제" 문구로 표시 | 미조치 — 보류(대장) |
| M3 | 중간 | CCTV 패널만 스테일 가드가 없다 — 8/29 판독이 "지금"으로 | ⚠️ 혼잡장은 σ 확대로 해결(§3.9) · CCTV 카드는 미조치 |
| M4 | 중간 | 시각 판단이 전부 뷰어 기기 시계 기준 | 미조치 — 다음 단계 |
| M5 | 중간 | 타일 서버만 죽으면 빈 배경에 마커만 남고 폴백이 없다 | 미조치 — 다음 단계 |
| M6 | 중간 | 사전 모드의 α=1.00이 측정값처럼 보인다 | 미조치 — 보류(대장) |
| M7 | 중간 | 수집은 하는데 화면에 없는 신호(edge_hit 경보 · 실시간 통제 메시지) | 미조치 — 다음 단계 |
| L1 | 낮음 | 표 3-3 번호 누락 | ✅ |
즉시 5건과 H2·H5는 결함을 재현하는 테스트를 먼저 써서 실패를 확인한 뒤 고쳤다. 신규 테스트 15건 중 13건이 그렇게 빨강→초록을 거쳤고, 2건은 기존 동작을 굳히는 회귀 가드라 처음부터 통과했다. 테스트는 26 → 41 → 45건이 됐고(§3.5), 이후 회차와 기능을 거쳐 9/8 기준 122건이다. 조치 자체가 만든 새 실패 모드 3건도 같이 닫았다 — 고치기 전에는 없던 위험이라 남겨 두면 순손실이다.
| # | 새로 생긴 위험 | 조치 |
|---|---|---|
| C2-a | pull --rebase가 충돌하면 저장소가 rebase 상태로 묶여 이후 모든 틱의 커밋이 실패한다(두 기기가 같은 파일을 고쳤을 때) | 실패 시 rebase --abort로 되돌리고 경보만 올린다. 자동 병합은 하지 않는다(사람이 판단할 일). 실제로 충돌하는 저장소 2개를 만들어 검증하는 통합 테스트 1건 |
| C3-a | 뜨자마자 죽는 크래시 루프면 30초마다 재기동 = 정상 주기의 10배로 API 쿼터를 태운다 | 10분 안에 5회 넘으면 재시도 간격을 300초로 늘린다. 영구 정지는 하지 않는다 — 밤중에 조작자가 없을 수 있어 자가복구를 남긴다 |
| 정규식-a | 9/1 혼잡장 작업 중 한 줄 함수를 여러 줄 정규식으로 교체하다 뒤따르는 RouteHeap·routeAstar가 통째로 지워졌다. 문법 검사는 통과했고 지도까지는 정상이라 네 커밋 동안 아무도 몰랐다 | 이전 커밋에서 인덱스 절단으로 복원(정규식 안 씀). 인라인 스크립트가 부르는 지역 함수가 전부 정의돼 있는지 보는 회귀 가드 추가 — 블록을 지우면 ['routeAstar']로 실패함을 역검증. 규칙은 저장소 CLAUDE.md에 |
전수 감사가 아니다. 1회차가 읽은 것은 nowcast.py · collector_api.py · publish.py · backtrack.py(출구 계산부) · run_all.sh · index.html · report.html과 data/derived/ 산출물이다. 읽지 않은 것은 collector_cctv.py · evaluate.py · exit_shares.py · feeder_leadlag.py, 쉬운 버전·피치 덱, 그리고 9/1에 새로 들어온 field.js(혼잡장) · routing/(경로탐색) · tools/demo.sh다. collector_cctv.py는 구역 밀도를 도달 지연 계산에 직접 먹이는 미감사 입력 중 가장 큰 것이고, 혼잡장은 공개 화면에서 가장 눈에 띄는 요소라 2회차의 1순위다. 결함 대장은 저장소 redteam-20260901.md 하나이며 이 절은 그 요약이다 — 상태가 바뀌면 그 문서가 먼저다. (2026-09-08 추기) 위에 적은 미감사 파일은 2회차가 읽었고(collector_cctv.py·field.js·routing/), 4회차는 다른 모델이 전체 diff 를 공격했다. 5~7회차는 코드가 아니라 실행에서 찾은 것이라 코드 감사 범위와는 별개다.
9/4 17:08 에 켠 파이프라인을 끄지 않고 9/6 01:01 까지 32시간 돌렸다. 전야제와 본번을 한 번의 운전으로 지났고, 본번 12시간 동안 5분마다 예측을 발행했다. 채점 숫자는 전부 src/evaluate.py --date 20260905(data/derived/eval_20260905.json)에서 가져왔다. 그 시각 화면은 운영·관람객 재생으로 그대로 열린다 — 배너 칩으로 20:05 → 23:02 여섯 시점을 오간다.
| 항목 | 값 |
|---|---|
| 발행 스냅샷 | 287개 — 12:00~24:00, 5분 간격, 자동 |
| 수집 | 서울시 API 9,147건 · CCTV 판독 33,120건 |
| 재기동 | 1회 — 16:44 수집 간격 전환(계획). 크래시 0 · 슬립 공백 0 |
| 여의나루 통제 실측 | 18:10~22:05 무정차 (공지 20:40~21:40). 19시 통제를 19:13 에 규칙에 추가했다 — H3 「19시 낙관」이 현장에서 확인됐다 |
| 쇼 종료 실시각 | 21:27 (계획 21:10). 현장에서 한 줄 기입 → 21:36 발행분부터 21시 유출 예측 76.6천 → 88.3천 |
| 화면 최대 부하 | 여의나루 22시 0.93(재개통 직후) · 샛강 0.85 — 「경계」까지, 「심각」 없음. 사전표의 1.00 [0.65~1.41] 안 |
| 시각 | 무엇을 | 왜 |
|---|---|---|
| 00:26 | 보행 밀도 사다리 여유 1.5 → 0.5명/m², 못 본 길의 가로 기본 1.5 → 0.8 | 한산한 새벽에 2.9km/h 로 읽혀 소요 시간이 부풀었다 (§3.10) |
| 17:55 | 서울시 구역 등급의 나이에서 API 발행 시차 28분을 뺐다 | 시차를 낡음으로 세어 σ 가 1.1 까지 커졌고 서울시 등급이 혼잡장에서 빠져 있었다 (M16) |
| 19:13 | 여의나루 통제에 19시를 추가했다 | 실측 조기 무정차 18:10~ (H3) |
| 22:20 → 22:31 | 속도 바닥 0.6m/s 를 10분 만에 철회하고 걷는 시간 ÷1.4 로 바꿨다 | 바닥은 주의·경계·심각을 한 속도로 뭉갠다. 배율은 등급 간 시간 차를 지킨다. 1.4 는 가정값 (§3.10) |
세 가지를 쟀다. ① 오늘 배율 α 가 어떻게 움직였나 ② 유출 곡선의 형태가 실측 승차와 맞나 ③ 같은 도시데이터를 쓰는 서울시 12시간 선행 예측은 얼마나 맞았나(기준선). 규모의 절대값은 실측(핫스팟 9역 30분 승차 합)과 우리 예측(출구 7곳)의 범위가 달라 비교하지 않는다 — 피크 대비 비율만 비교한다.
| 시각 | α | 관측 | 비고 |
|---|---|---|---|
| 12:01 | 1.00 | 0 · 0 | 사전분포 [0.73~1.38] |
| 12:47 | 1.36 | 1 · 0 | 하루 최고 [1.07~1.68] — 첫 관측 한 건이 사전을 밀어냈다(C1 의 모습이 본번에도 있었다) |
| 14:02 | 1.10 | 3 · 0 | |
| 16:03 | 1.02 | 7 · 0 | |
| 18:04 | 0.99 | 12 · 0 | 이후 여의나루 무정차로 하차 관측 종료 |
| 20:00 | 0.95 | 13 · 3 | 귀가측 관측 시작 |
| 21:36 | 0.90 | 13 · 6 | 쇼 종료 21:27 기입 직후 |
| 22:06 | 0.89 | 13 · 7 | 화면 최대 부하 시각 |
| 23:57 | 0.91 | 13 · 10 | 마감 [0.86~0.97] — 화면 밴드 ±6%. 실제 오차 하한은 §3.4 상자의 0.42~0.44 로 읽는다 |
| 시각 | 19시 | 20시 | 21시 | 22시 | 23시 |
|---|---|---|---|---|---|
| 실측 | 0.09 | 0.08 | 0.40 | 1.00 | 0.92 |
| 예측 | 0.25 | 0.38 | 0.68 | 1.00 | 0.41 |
맞힌 것 — 피크 시각 22시가 일치했고 형태 상관은 r 0.66 이다. 놓친 것 — 23시 꼬리. 실측은 피크의 92% 가 23시에도 이어졌는데 예측은 41% 로 꺼졌다. 원인 후보는 둘이다. ① 감쇠 형태 \(f_s(h)\) 가 2024·2025 실적에서 왔는데 2026 은 여의나루 조기 무정차(18:10~22:05)로 승차가 22시 뒤로 밀렸다. ② 쇼 종료 +17분을 반영해도 꼬리의 폭은 늘지 않는다. 조치는 보류했다 — 2026 실측 하루로 꼬리 파라미터를 다시 맞추면 과적합이다. 결함 대장 M15.
| 시각 | 실측 | 12시간 전 예측 | 오차 |
|---|---|---|---|
| 18시 | 23,000 | 6,250 | 73% |
| 20시 | 43,000 | 6,750 | 84% |
| 21시 | 49,000 | 7,250 | 85% |
| 22시 | 53,000 | 5,750 | 89% |
| 23시 | 13,000 | 3,750 | 71% |
하루 MAPE 0.56, 예측 범위 적중 4%. 같은 도시데이터를 쓰는 공식 선행 예측이 저녁 피크를 9배 낮게 봤다. 우리 α 를 5분마다 관측으로 갱신해야 하는 이유의 실측 근거다. 이 표는 우리 모델과의 직접 비교가 아니라 "선행 예측만으로는 안 된다"는 기준선이다.
이 밖에 실측이 확인해 준 것 — 조기 무정차의 방향(H2 의 "공지 시각 + 예년 이력" 병기가 맞았다) · 쇼 종료 기입 경로(C4)가 본번에서 한 번 작동했다 · 실측 장에서 최단시간 경로가 실제로 바뀌었다(36건 중 11건, §3.10 · M14 부분 닫힘) · 서울시 API 발행 시차 28.8분(2회차 가설 확정, M16). 미검증으로 남은 것 — 대기 분 문구(스톱워치 실측 없음).
| 데이터셋 | 제공·ID | 사용 범위 | 용도 |
|---|---|---|---|
| 서울교통공사 역별 일별 시간대별 승하차인원 | 서울 열린데이터광장 OA-12921 | 2024·2025 연간 CSV (1~8호선, 9호선 미포함) | 출구별 실측 인파 E_st · 처리용량 · 백테스트 · 피더 역추적 |
| 티머니 교통카드 역별 일별 승하차 | 서울 열린데이터광장 OA-12914 | 2024-10 · 2025-09 월 파일 (1~9호선) | 9호선 규모 · 용량 비례 추정 |
| KT 수도권 생활이동 — 목적별 OD | 서울 열린데이터광장 OA-22300 (서울시×KT, 통신 기반 전수화 추정) | 축제일 2일(2024-10-05 · 2025-09-27) + 대조 토요일 | 유출 시간 곡선 · 출발지(구 단위) 구성. 목적코드 3=귀가 (빅데이터캠퍼스 자료안내서 B078로 확정) |
| KT 생활이동 — 수단별 OD | 서울 열린데이터광장 OA-22657 | 축제일 1일 | 지하철 비중 (수단코드 6=지하철, 코드표 미공개라 "추정" 표기) |
| 서울 생활인구 (행정동) | 서울 열린데이터광장 OA-14991 | 2024-10 · 2025-09 월 파일 (여의동 11560540) | 규모 외부 검증 (§3.8) — 당일 4.4~4.8배 · 전야 동 단위 희석 |
| 서울 실시간 도시데이터 (citydata) | data.seoul.go.kr/SeoulRtd API | 핫스팟: 여의도한강공원(POI105)·여의도·여의서로 + 피더 12곳, 5분 주기 | 당일 α 관측(30분 승하차) · 피더 감시 · 서울시 12시간 예측과 오차 비교 |
| TOPIS 교통 CCTV | topis.seoul.go.kr 공개 HLS | 여의도 반경 23대 — 720p HD 9대, 나머지 720×480 | 보행 밀도 → 보행속도 보정 · 혼잡장 관측. 프레임 미저장(집계만) |
| 2026 축제 공식 공지 | hanwhafireworks.com | 공지 6호 등 | 통제 규칙(여의나루 20:40~21:40 · 여의동로 전면통제) · 쇼 21:10 종료 |
| 2025 서울시 보도자료 | 서울시 | 2025 축제 교통대책 | 통제 규칙 시드 (여의동로 14~23시 전면통제, 마포대교 하위 1차로 임시 보행로, 버스 26노선 증차) |
| 지하철 실시간 도착 | 서울 열린데이터광장 realtimeStationArrival | 여의도권 4역, 17~23시 (전용 키 6개 틱 회전 배정, 키당 ~56회/일) | 당일 화면 참고 정보 |
| OpenStreetMap 도로 기하 | OSM Overpass API | 여의도 일대 4개 도로 | CCTV 관심영역 면적 산출 (차로 수·연장) |
| OpenStreetMap 보행망 | OSM Overpass API (© OpenStreetMap contributors, ODbL) | 카메라 23대를 감싸는 범위. 노드 9,219 · 간선 26,042 (2026-09-01 구축) | 혼잡 회피 경로탐색 그래프 docs/data/routing/walk_graph.json |
| 서울시 한강교량 제원 | 서울시 공표 자료 | 마포대교 1,390×25m · 원효대교 1,120×20m | 교량 위 관심영역 면적 |
원본 대용량 파일은 저장소 밖 보관(공개 Release 예정). 전 데이터셋 재다운로드 명령은 저장소 data/README.md.
benchmark-crowd-systems.md파일:줄 근거 → 실패하는 테스트 → 수정). AI 활용 기록은 커밋 로그와 저장소 문서에 단계별로 남김field.js 단언 22개) · MapLibre GL + OpenFreeMap (지도) · OpenStreetMap (보행망, ODbL) · 서체 (마루부리·Pretendard·IBM Plex Mono) · GitHub Pages (호스팅)data/derived/*.json에 산출 근거와 함께 저장돼 있고, data/README.md의 명령으로 원본에서 재현 가능하다.
추정치는 본문·데이터 모두 "추정" 표기. 원본 대용량 데이터는 저장소 외부 보관(공개 Release 예정). 기준일 2026-09-08.