사용 안내
처음 쓰시는 분을 위한 안내입니다. 이 도구가 무엇을 계산하는지, 무엇을 입력하고 결과를 어떻게 읽는지 순서대로 설명합니다.
처음 쓰신다면
세 단계면 끝납니다 — 실행하고, 기다리고, 결과를 봅니다. 위쪽 메뉴의 1 실행 → 2 결과가 이 순서이고, 3 데이터는 CSV 원본이 필요할 때만 씁니다.
- 계획 실행 — 값을 그대로 두고 “계획 실행”을 누릅니다 기본값이 이미 채워져 있습니다. 처음에는 아무것도 바꾸지 마세요. 실행 화면 →
- 끝날 때까지 기다립니다 — 진행 단계가 화면에 나옵니다 대여소를 묶는 단계가 전체 시간의 3분의 2 이상을 차지합니다. 화면은 3초마다 진행 상황을 받아 바뀐 칸만 고칩니다. 대여소 수집·순수요 계산은 한 번만 하고, 군집·경로·지표는 시간대마다 다시 계산하기 때문에 고른 만큼 늘어납니다. 아직 이 서버에 실행 기록이 없어 숫자를 적지 않습니다 — 한 번 돌리고 나면 그 기록에서 뽑아 보여 줍니다. 기록이 쌓이면 여기에 나옵니다
- 결과를 봅니다 — 작업지시서를 기사에게 넘기고, 지도로 경로를 확인합니다 현장에 내보낼 것은 작업지시서입니다(차량 한 대 = 한 장, 출발 직전 “지금 재고와 대조하기”). 지도는 경로를 눈으로 확인할 때, 지표는 “이번 계획이 쓸 만한가”를 판단할 때 봅니다. 작업지시서 →
무엇을 계산하나
한 문장으로: 지금 자전거가 남는 곳에서 빼내 모자랄 곳으로 미리 옮기는 계획을 만듭니다. 계산은 다섯 단계를 거칩니다.
- 지금 재고를 확인합니다 타슈 API에서 대여소마다 자전거가 몇 대 있는지 실시간으로 받아옵니다.
- 얼마나 필요할지 추정합니다 — 목표 재고 과거 같은 조건(같은 시간대, 같은 평일/휴일)에서 이 대여소의 순수요가 평균 얼마였고 얼마나 들쭉날쭉했는지를 보고, 넉넉하게 잡습니다.
- 대여소를 덩어리로 묶습니다 — 군집 차량 한 대가 한 덩어리를 맡습니다. 가까운 것끼리, 일감이 고르게 나뉘도록 묶습니다. 몇 덩어리로 나눌지는 그 회차의 일감이 정합니다 — 옮길 자전거가 많고 들를 대여소가 흩어져 있으면 더 많은 차가 나갑니다. 지난 실행에서는 회차당 14대가 나갔습니다(중앙값).
- 덩어리 안에서 어디서 얼마를 옮길지 정합니다 한 덩어리 안에서 남는 대여소와 모자란 대여소를 짝지어, 가까운 곳끼리 많이 옮기도록(옮기는 대수 × 이동시간의 합이 가장 작게) 배분합니다. 덩어리 경계를 넘는 이동은 없습니다.
- 차량이 도는 순서를 짭니다 — 경로 차고지에서 출발해 맡은 대여소를 다 들르고 돌아옵니다. 순서와 예상 시간은 대여소 사이 직선거리에 실측 도로 계수를 적용해 계산합니다 — 구간마다 고정 5분 20초 + 32 km/h로, TMAP 실도로 소요시간에 맞춘 값입니다. 지도에 그리는 선은 가능하면 실제 도로(TMAP)를 따릅니다.
지금 설정
| 보유 차량 | 21대 |
|---|---|
| 한 회차 투입 상한 | 최대 21대 |
| 실제로 나간 대수 | 회차당 14대 |
| 한 대 적재 용량 | 최대 10대 |
| 이동시간 모형 | 고정 5분 20초 + 32 km/h (실도로 계수) |
| 한 회차 시간 예산 | 120분 |
투입 상한은 말 그대로 상한입니다. 실제로 몇 대가 나갈지는 그 회차의 일감이 정합니다. 보유 차량 대수와 회차당 투입 상한은 실행할 때마다 폼에서 바꿀 수 있고, 적재 용량·주행 속도·시간 예산은 코드 설정값입니다.
오늘은 평일입니다
휴일 = 주말 + 공휴일. 달력으로 자동 판정합니다.
평일과 휴일은 자전거가 흐르는 방향 자체가 다릅니다. 평일 아침에 사람이 몰리는 대여소가 휴일에는 텅 비기도 합니다. 그래서 두 날을 한 통계로 섞으면 서로 상쇄돼 “아무 데도 옮길 필요가 없다”는 잘못된 답이 나옵니다. 한 번에 한쪽만 계획합니다.
입력 항목
실행 화면의 각 칸이 무슨 뜻인지입니다. 처음에는 기본값 그대로 두시면 됩니다.
| 항목 | 무엇인가 | 언제 바꾸나 |
|---|---|---|
| 실행 이름 | 이번 계획에 붙일 이름. 결과 파일과 기록에 그대로 들어갑니다. | 조건을 바꿔 여러 번 돌리고 서로 비교할 때. 이름이 같으면 덮어씁니다. |
| 순수요 기간 | 대여소별 평균·편차를 뽑을 달. 계산해 둔 달만 목록에 나옵니다
(25년 11월 표기). 기본값은 가진 것 중 가장 최근 달입니다.
한 달치만 보는 것이 아닙니다 — 계획 대상 달(웹 실행은 오늘이 속한 달)의 첫 14일 순수요가 계산돼 있으면 계절 배율을 곱해 수준을 맞추고, 없으면 이 달 통계를 그대로 씁니다. 적용됐는지는 실행 로그의 ‘계절 보정’ 줄에서 확인하세요. 과거를 더 넣어 보면 오히려 나빠집니다(직전 1달 → 같은 계절 → 전체 순으로 예측 오차가 커집니다). 값이 다른 달이 섞여 중심이 틀어지기 때문이고, 12개월 자료로 확인했습니다. 그러니 최근 1달을 쓰는 것은 자료가 모자라서가 아니라 재 보고 고른 것입니다. |
계절이 바뀌었을 때. 여름 계획에 겨울 수요를 쓰면 맞지 않습니다. 평소엔 기본값(최근 달) 그대로 두세요. |
| 시간대 | 하루 중 어느 회차를 계획할지. 창은 넷입니다(낮 셋은 5시간, 자정을 넘기는
_20_05는 9시간):
_05_10(05~10시 (출근)), _10_15(10~15시 (낮)), _15_20(15~20시 (퇴근)), _20_05(20~05시 (야간)).
고르지 않습니다. 재고를 받은 시각에 출발 앞당김 30분을 더한 시각이 드는 회차 하나를
세웁니다(23시 11분이면 23시 41분이 드는 20~05시). |
계획은 그 실행에서 받은 재고 한 장으로 세웁니다. 그래서 그 재고로 곧 출발할 회차만 맞습니다. 다음 회차 계획은 그 회차 출발 무렵에 다시 실행하세요. 'API 수집 생략'을 켜면 물려받는 재고의 시각으로 정합니다. |
| 요일 구분 | 평일용인지 휴일용인지. 자동이면 계획 대상일을 달력으로 판정합니다. | 평소엔 자동. 미리 휴일 계획을 만들어 둘 때만 직접 고릅니다. |
| 보유 차량 대수 | 오늘 실제로 굴릴 수 있는 트럭 수. | 정비나 결원으로 차가 빠졌을 때. 줄이면 남는 차량은 배정에서 빠집니다. |
| 회차당 투입 상한 | 한 번에 동시에 내보낼 수 있는 최대 대수. 실제 대수는 그 회차의 일감(옮길 자전거 수·들를 대여소 수)이 정합니다. | 현장에서 한 번에 낼 수 있는 차·기사가 정해져 있을 때 줄입니다. 줄여서 일감을 다 못 담으면 몇 대가 모자란지 실행 기록에 남습니다. |
| 원천 대여 이력 CSV | 대여이력이 DB에 아직 없는 기간을 계산할 때만 읽는 원본 CSV. 그 기간 한 달치만 담긴 파일이어야 합니다 — 여러 달이 섞인 파일을 넣으면 전부 그 한 달로 계산됩니다. 목록의 기간이 이미 DB에 있으면 이 칸은 쓰이지 않습니다. | 평소엔 건드리지 않습니다. 새 달은 순수요를 먼저 계산해야 기간 목록에 나오므로, 그 계산을 터미널에서 한 뒤 이 폼에서 고르세요. |
| API 수집 생략 | 실시간 재고를 새로 받지 않고 가장 최근 실행의 재고를 물려받습니다. 어느 실행에서 물려받았는지는 로그에 남습니다. | 방금 받아 뒀고 재고가 안 변했을 때만. 평소엔 끄세요 — 그 시점 재고로 계획을 세우게 됩니다. |
| EDA 생략 | 탐색용 분석 그래프를 만들지 않습니다. | 계획 결과에는 영향이 없고 시간만 줄어듭니다. 켜 두세요. |
결과 읽는 법
화면 세 곳에 결과가 나뉘어 있습니다. 목적이 서로 다릅니다.
🗺 지도 — 경로를 눈으로 확인
대여소를 어떤 순서로 들르는지 지도 위에 그린 것입니다. 기사에게 줄 수량표는 옆의 작업지시서입니다. 지도는 새 창으로 열어 인쇄하거나 화면째 전달할 수 있습니다.
📋 작업지시서 — 기사에게 줄 종이
차량 한 대가 한 장입니다. 들를 순서·대여소·싣고 내릴 수량·차에 남는 대수가 표로 나옵니다. 인쇄하면 차량마다 쪽이 나뉩니다. 출발 직전에 “지금 재고와 대조하기”를 누르면 계획 대상 대여소만 다시 조회해 집행 가능한지 알려 줍니다. 작업 중에는 기사가 현장 앱 경로 화면에서 “지금 재고로 재판정”을 누르면 끝낸 곳은 빼고 남은 대여소만 다시 판정합니다 — 앞에서 덜 실었으면 뒤에서 내릴 수 있는 대수도 그만큼 줄여 셉니다.
지표가 뜻하는 것
| 지표 | 뜻 | 어떻게 볼까 |
|---|---|---|
| 평균 개선률 | 목표 재고까지 모자란 양을 계획이 몇 % 메웠는가. | “계획을 얼마나 지켰나”이지 “수요를 맞췄나”가 아닙니다. 아래 한 번에 닿는 범위와 같이 보세요. |
| 한 번에 닿는 범위 · 격차 | 계획 전에 목표까지 모자란 양이 트럭 적재 용량(최대 10대) 안이라 한 번 방문으로 채울 수 있었던 대여소의 비율과, 모자란 양의 중앙값 · 최댓값. | 성과가 아니라 일감의 크기입니다 — 계획을 세우기 전에 정해집니다. 낮으면 한 회차로는 못 푸는 일이 많았다는 뜻이라 개선률이 낮게 나와도 계획 탓이 아닙니다. 그래서 맨 위 타일이 아니라 표의 참고 열(‘모든 열 보기’)에 둡니다. |
| 결품 시간 | 자전거가 한 대도 없어 빌리려던 사람이 그냥 돌아가는 시간 (대여소·하루 평균). | 이용자 불편에 가장 가까운 지표입니다. 다만 집행 후 관측이 아니라 시뮬레이션입니다. |
| 이동거리 | 모든 차량이 움직인 거리의 합. | 연료·인건비에 직결됩니다. 개선률이 같다면 짧은 쪽이 낫습니다. |
| km당 개선 | 1km 움직여 불균형을 몇 대 줄였는가(대/km). | 투입 대비 효율입니다. 조건을 바꿔 가며 비교할 때 유용합니다. |
| 최장 작업 · 예산 준수 | 가장 오래 걸린 차량의 작업 시간과, 120분 안에 작업을 끝낸 차량의 비율. | 넘긴 회차는 붉은 배경에 ⚠로 표시됩니다. 시간 예산은 운영 제약이 아니라 연구에서 세운 목표라 넘겨도 집행은 됩니다 — 다만 겨냥한 시간대를 지나 효과가 줄 수 있습니다. |
| 차량 간 작업량 차이 | 가장 적게 일한 차량과 많이 일한 차량의 누적 시간 차이. | 작을수록 고르게 나뉜 것입니다. 특정 차량에 일이 몰리는지 봅니다. |
이럴 땐
| 상황 | 어떻게 하나 |
|---|---|
| 성과 지표의 "수요 예측은 얼마나 맞나"가 비어 있습니다 | 그 절은 목표 재고의 전제(평균 순수요 mu)가 다음 달을 얼마나
맞히는지 재는 것이라 계획 실행과 별개로, 터미널에서 한 번 돌려야 채워집니다.
python tools/backtest_demand.py
한 달 자료로 만든 mu가 다음 달 수요를 얼마나 맞혔는지 월쌍으로 쌓아 둡니다. 평일·휴일은 --day-type으로 따로 재고, 값이 남으면
docs/분석/KPI.md E장에서 읽는 법을 설명합니다. |
| 실행이 실패했습니다 | 실행 화면에서 그 작업을 열면 진행 단계에 붉게 표시된 곳이 있습니다. 거기서 멈춘 것이니, 아래 로그의 마지막 부분에서 원인을 봅니다. 앞 단계 결과가 다음 단계 입력이라 중간부터 다시 돌릴 수는 없습니다. |
| 새 실행 버튼이 없습니다 | 이미 하나가 돌고 있습니다. 같은 자리에 진행 상황 링크가 나옵니다. 기다리거나, 그 화면에서 실행 중단을 누르세요. |
| 예산을 넘긴 회차가 있습니다 | 먼저 폼의 회차당 투입 상한을 보유 대수보다 줄여 두었는지
보세요 — 줄였다면 일감보다 적게 나가 한 대가 맡는 덩어리가 커집니다(몇 대가
모자랐는지 실행 기록에 남습니다). 기본값에서는 상한이 보유 대수(21대)와
같아 상한이 원인이 아니고, 그 회차의 한 덩어리에 일감이 몰린 것입니다.
시간 예산은 운영 제약이 아니라 목표라 넘겨도 집행은 됩니다. 넘기지 않게
짜려면 터미널에서 --enforce-time-budget으로 실행하세요(예산을 넘는
작업은 미집행으로 남습니다). 상한을 10 → 15~18대로 올려 초과가 60% → 2%로
떨어진 실측은 상한이 10대이던 1.19.1 이전 이야기입니다. |
| 결과가 비어 있습니다 | 아직 한 번도 끝까지 돌지 않았거나, 도중에 실패했습니다. 실행 이력에서 마지막 작업의 상태를 확인하세요. |
| 차가 몇 대 빠졌습니다 | 실행할 때 보유 차량 대수를 실제 대수로 줄이세요. 남는 차량은 배정에서 자동으로 빠지고, 나중에 늘리면 다시 들어옵니다. |
| 계획을 세워 뒀는데 재고가 바뀌었습니다 | 작업지시서에서 “지금 재고와 대조하기”를 누르세요. 계획 대상 대여소만 다시 조회해 가능·부족·넘침·불가로 나눠 줍니다. 계획을 자동으로 바꾸지는 않습니다 — 몇 대를 조정할지는 현장에서 정합니다. 차이가 너무 크면 계획을 다시 실행하는 편이 낫습니다. |
| 표를 원하는 순서로 보고 싶습니다 | 열 제목을 누르면 그 열로 정렬됩니다. 한 번 더 누르면 반대 방향입니다. 숫자 열은 크기순, 글자 열은 가나다순이고 빈칸은 늘 맨 뒤로 갑니다. 링크만 있는 열(‘열기’·‘바로 보기’)은 정렬되지 않습니다. |
| 지난 결과를 다시 보고 싶습니다 | 지우지 않는 한 남아 있습니다. 실행 화면의 저장된 실행 표에서 이름으로 찾거나, 지표·차량 화면 위쪽의 실행 이름 버튼으로 걸러 보세요. |
재고 수집 — 실측 재고를 쌓는 일
계획과는 별개로, 대여소 재고를 10분마다 받아 쌓는 수집기가 따로 돕니다. 쌓인 기록은 재고 수집 화면에서 보고, 계획이 복원한 결품을 실제 관측과 맞대어 보는 데 씁니다.
| 어떻게 시작하나 | 저장소 폴더의 PowerShell에서 한 번만 등록합니다 —
.\scripts\collector.ps1 install -Window 07:00-23:00 -IncludeHolidays.
⚠️ 인자를 빼면 기본값인 평일 09:00–17:00으로 등록되고, 이미 등록된
작업까지 그 값으로 덮어씁니다. |
| 멈추고 다시 켜기 | pause(작업은 남기고 안 깨움) ·
resume · uninstall(작업 삭제). 셋 다
모은 데이터는 지우지 않습니다. 상태는 status로 봅니다. |
| 언제 비나 | PC가 꺼져 있거나 절전으로 내려가면 그 구간이 통째로 빕니다. 망이 끊기면 스크립트는 돌지만 값을 못 받아 실패로 남습니다 — 수집 화면이 둘을 갈라 보여 줍니다. |
용어
| 말 | 뜻 |
|---|---|
| 순수요 | 한 대여소에서 빌려 나간 수 − 반납된 수. 양수면 자전거가 빠져나가는 곳(채워 줘야 함), 음수면 쌓이는 곳(빼내야 함)입니다. |
| 목표 재고 | 그 시간대를 버티려면 몇 대가 있어야 하는가. 평균 수요에 여유분을 더해 잡습니다 — 평균만 맞추면 절반은 모자라기 때문입니다. |
| 군집 | 가까운 대여소를 묶은 덩어리. 차량 한 대가 한 덩어리를 맡습니다. 덩어리 수 = 그 회차에 나가는 차량 수이고, 일감에 따라 회차마다 달라집니다. |
| 회차 | 한 번 나갔다 돌아오는 것. 화면의 _10_15 같은 표시는
그 회차가 겨냥한 시간대입니다. |
| 작업 시간 | 차고지를 떠나 대여소를 다 돌고 차고지로 돌아올 때까지입니다. 이동 시간 + 자전거를 싣고 내리는 시간이고, 주행은 직선거리에 실도로 계수(고정 5분 20초 + 32 km/h)를 적용해 잡습니다. |
| 시간 예산 | 한 회차를 마치는 목표 시간(120분). 연구에서 세운 값이라 운영 제약이 아닙니다 — 넘겨도 계획은 그대로 집행할 수 있고, 겨냥한 시간대를 지나 효과가 줄어들 뿐입니다. |
| 실행 이름 | 한 번의 계산에 붙인 이름. 결과 파일과 기록을 이 이름으로 묶습니다. |
| 휴일 | 주말 + 공휴일. 달력으로 자동 판정합니다. |
계획이 쓰는 기준
현장에서 “왜 이 대여소는 안 건드리지?”, “왜 여기까지만 채우지?” 라는 질문이 나오는 자리입니다. 코드에만 있던 값을 여기에 밝혀 둡니다.
| 기준 | 값 | 왜 |
|---|---|---|
| 몇 곳까지 손대나 | 수거·배송 각 상위 50곳 | 작업량이 큰 순으로 싣는 곳·내리는 곳을 각 50곳까지만 보고, 그 뒤 싣는 양과 내리는 양 중 적은 쪽에 맞춰 한 번 더 자릅니다. 보유 차량 21대로 집행할 수 있는 규모에 맞춘 값이라, 모자라거나 남아도 순위 밖이면 빠집니다 — 실제로 대상을 가르는 것은 아래 문턱보다 이 제한입니다. |
| 얼마부터 작업 대상인가 | 2대 초과 | 모자라거나 남는 양이 2대 이하면 손대지 않습니다. 한두 대를 맞추러 차를 보내는 것이 손해이고, 그 정도 차이는 이용자가 몇 시간 안에 스스로 메웁니다. (지금 자료에서는 위 순위 제한이 먼저 걸려 이 문턱으로 빠지는 대여소는 거의 없습니다.) |
| 얼마까지 채울 수 있나 | 거치대 × 1.5 | 거치대 수를 그대로 상한으로 쓰지 않습니다. 자전거는 거치대 밖에도 세울 수 있고, 거치대가 5대뿐인 대여소에서 상한을 딱 맞추면 수요를 아예 못 담기 때문입니다. 재고 대조의 “넘침” 판정도 같은 값을 씁니다. ⚠️ 현장 확인이 안 된 값이라, 운영 규칙이 다르면 알려 주세요. |
| 한 대에 몇 대를 싣나 | 최대 10대 | 대전교통공사 관제센터에 유선으로 확인한 최대치입니다 (답변: 통상 7대, 많이 실어야 10대). 경로는 이 최대치를 넘기지 않도록 싣고 내리는 순서를 섞으므로, 평소처럼 적게 실으면 차가 더 필요할 수 있습니다. |
| 얼마나 넉넉히 잡나 | 평균 + 1.99σ | 평균만 맞추면 절반은 모자랍니다. 12개월 실측 백테스트로 정한 값이며, 관행값 1.65가 아닙니다. |
더 알아보기
계산 근거와 설계 판단은 프로젝트 폴더의 문서에 있습니다.
docs/분석/KPI.md |
지표를 왜 이렇게 정의했고 무엇을 못 재는지 |
|---|---|
docs/구현/FLEET.md |
차량 배정과 로테이션 규칙 |
docs/분석/DEMAND_DISTRIBUTION.md |
목표 재고를 잡는 근거와 그 전제의 한계 |
docs/구현/WEBAPP.md |
이 대시보드의 구조와 API |
python -m webapp은 같은 네트워크의 다른 기기(휴대폰 등)에서도 접속되도록
0.0.0.0:8000으로 뜹니다. 로그인이 없으니 신뢰하는 사내망에서만 켜고,
이 PC에서만 쓰려면 uvicorn webapp.app:app --host 127.0.0.1 --port 8000으로
띄우세요.