Urban Waste Statistics Simulation

실제 통계와 비슷한 폐기물 도시 만들기

과제의 요구사항은 알고리즘을 응용해 사회의 문제에 접근해 보는 것이었다. 처음부터 폐기물을 주제로 정한 것은 아니었다. 사용할 만한 공공 데이터를 먼저 찾아보다가, 오히려 데이터가 보여주지 않는 부분에서 주제를 발견했다.

폐기물 자료는 시군 전체의 발생량처럼 큰 단위로는 찾을 수 있었다. 하지만 그 총량이 주택, 상점, 학교, 공장과 병원 같은 작은 구동 단위에서 어떻게 만들어지는지는 유추하기 어려웠다. 총량만 놓고 보면 인구 4만 명인 작은 지역과 30만 명인 도시를 같은 기준으로 비교하기도 힘들다. 큰 도시가 더 많은 폐기물을 배출하는 것은 자연스럽지만, 그렇다고 더 비효율적인 도시라고 바로 말할 수는 없기 때문이다.

그래서 방향을 반대로 잡았다. 작은 단위의 건물과 인구, 폐기물 계수를 먼저 만들고, 사용자가 도시 조건을 입력했을 때 공식 통계와 비슷한 규모의 총량이 나오도록 도시를 조립해 보기로 했다.

도시 A와 도시 B를 생성하고 하루 폐기물 발생량을 비교하는 시뮬레이션
도시 A와 B를 서로 다른 조건으로 구성한 뒤 하루치 폐기물을 생성한다. 건물을 선택하면 인구와 세부 폐기물 발생량을 확인할 수 있다.

건물 하나에서 도시 전체로 올라가기

도시는 주거 시설, 음식점과 카페, 상점, 학교, 공장, 병원, 오피스, 공원, 공사 현장과 공공 기관으로 나눴다. 각 건물에는 면적과 거주·종사·유동 인구가 있고, 건물 유형에 따라 상주 인구와 방문 인구의 배출계수가 다르게 적용된다.

주거지는 거주 인구의 비중이 크고, 음식점은 유동 인구와 음식물류 폐기물의 비중이 크다. 공사 현장과 병원, 공장에서는 생활폐기물 외에 건설·의료·사업장 폐기물을 별도로 더한다. 계산한 값은 음식물, 종이, 비닐, 플라스틱 등 16개 세부 항목으로 나눈 뒤 다시 종량제봉투, 음식물류, 재활용가능자원, 대형·건설·의료·사업장 폐기물의 7개 범주로 집계한다.

생활폐기물
  = (거주 인구 + 종사 인구) × 상주 배출계수
  + 유동 인구 × 방문 배출계수

특수 폐기물
  = 인구·방문자·건물 면적 × 업종별 계수

도시 총량
  = 모든 건물의 생활폐기물과 특수 폐기물 합계

실제 통계는 정답지가 아니라 보정 기준이었다

초기 버전은 도시의 구조와 폐기물 발생 과정을 화면에 만드는 데 집중했다. 이후 생성된 숫자가 임의의 게임 수치에 머물지 않도록 실제 통계를 기준으로 보강했다.

제6차 전국폐기물통계조사의 1인당 생활폐기물 950.6g/일과 종량제 330.8g, 음식물류 310.9g, 재활용가능자원 308.8g을 세부 구성비의 기준으로 삼았다. 후속 보정에서는 2023년 전국 생활폐기물 1.2kg/일·인 수준도 전체 규모를 확인하는 비교 기준에 넣었다.

공식 수치를 모든 건물에 똑같이 곱하지는 않았다. 그렇게 하면 주거지와 업무지구, 공장지대의 차이가 사라진다. 대신 공식 통계는 도시 전체가 도달해야 할 범위를 잡는 데 사용하고, 내부에서는 건물 유형별 인구 밀도와 배출계수, 폐기물 구성비를 다르게 두었다. 목표는 특정 도시를 그대로 복제하는 것이 아니라, 아무 숫자나 생성하는 대신 대한민국 통계와 비슷한 규모와 분포를 가진 합성 도시를 만드는 것이었다.

사용한 통계의 세부 수치는 제6차 전국폐기물통계조사 결과에서 확인할 수 있다.

가장 어려웠던 것은 비례 보정이었다

무작위로 건물을 배치하면 설정창에서 예상한 인구와 실제 화면에 만들어진 인구가 달라진다. 건물 크기와 유형이 매번 달라지고, 충돌 검사에서 일부 후보가 탈락하기 때문이다. 도시 모양은 자연스럽게 바뀌어야 하지만 통계 합계는 사용자가 입력한 목표와 맞아야 했다.

그래서 배치가 끝난 뒤 거주·종사·유동 인구를 각각 비례 스케일링했다. 현재 합계를 구하고 목표값과의 비율을 모든 건물에 적용하되, 반올림으로 남는 차이는 마지막 건물에서 맞췄다. 건물 사이의 인구 비율을 유지하면서 도시 전체 합계를 목표에 맞추는 방식이다.

목표 폐기물도 같은 생각으로 처리했다. 현재 도시 조건에서 배율 1일 때의 예상 폐기물을 먼저 계산하고, 사용자가 입력한 톤/일과의 비율을 폐기물 배율에 반영했다. 작은 지역과 큰 도시를 입력해도 같은 생성기를 사용할 수 있는 이유가 이 보정 단계에 있다.

도시의 목표 인구와 폐기물 발생량, 건물 구성을 조절하는 설정 화면
목표 거주·종사·유동 인구와 폐기물 톤/일을 입력하면 기준 추정치와의 비율을 계산해 도시 설정에 반영한다.

두 도시를 나란히 둔 이유

이 프로젝트에서 도시 A와 B는 단순한 좌우 화면이 아니다. 예를 들어 A에 인구 4만 명 규모의 작은 생활권을, B에 인구 30만 명 규모의 도시를 입력하면 폐기물 총량만으로는 B가 항상 크게 나온다. 분석에서는 총량을 거주인구와 유효인구 기준으로 다시 나누고, 재활용 비율과 시설 유형별 발생량을 함께 봐야 두 도시 중 어느 쪽이 상대적으로 효율적인지 이야기할 수 있다.

시뮬레이션은 이 비교에 필요한 CSV를 만든다. 별도로 만든 분석 대시보드는 CSV를 읽어 도시와 시설 유형별로 그룹화하고, 총폐기물·인구·재활용가능자원을 한 번의 순회로 누적한다. 발생량이 큰 항목은 최소 힙으로 Top-K를 뽑고, 도시 규모 차이는 인구 기준 정규화로 줄였다.

즉, 생성기에서는 “이 조건의 도시는 어떤 데이터를 만들까”를 보고, 분석기에서는 “규모가 다른 두 도시를 어떤 기준으로 비교할까”를 본다. 두 페이지를 나눈 덕분에 합성 데이터 생성과 통계 해석을 각각의 알고리즘 문제로 다룰 수 있었다.

화면에 보이는 도시에도 알고리즘이 들어갔다

건물 유형은 설정한 가중치를 누적합 배열로 만든 뒤, 난수가 속한 구간을 이진 탐색해 선택한다. 도로는 7개의 레이아웃 함수를 테이블처럼 두고 설정값에 맞는 함수를 호출한다. 새 건물 후보는 점과 선분 사이의 최단거리로 도로와의 간격을 확인하고, 기존 건물과의 중심거리도 순차 검사해 겹침을 막는다.

도시 통계는 건물 유형과 폐기물 종류를 키로 쓰는 해시 테이블에 누적했다. 덕분에 시각적인 HTML 화면은 작은 도시가 계속 움직이는 것처럼 보이지만, 내부에서는 가중치 선택, 기하 계산, 충돌 검사, 비례 스케일링과 그룹 집계가 차례로 실행된다.

두 도시를 화면에 만들었다

첫 웹 시뮬레이션을 올리고, 같은 날 목표 통계를 직접 입력하는 기능과 실제 통계 기반 보정을 추가했다.

휴대폰에서도 도시를 비교했다

설정창과 비교 화면이 작은 화면에서도 이어지도록 모바일 UI를 보강했다.

생성과 분석을 하나의 흐름으로 연결했다

CSV 분석 대시보드를 만들고, 시뮬레이션의 자료구조와 알고리즘을 누적합·이진 탐색·충돌 검사·비례 보정 중심으로 다시 정리했다.

숫자보다 먼저 반응이 온 것은 화면이었다

주변에서는 공식 통계를 사용한 계산보다 건물과 자동차가 움직이고 두 도시가 나란히 나타나는 HTML 화면을 먼저 재미있어했다. 복잡한 표부터 보여주는 대신 도시가 만들어지고 폐기물이 쌓이는 모습을 앞에 둔 선택이 프로젝트를 이해하는 데 도움이 됐다.

이 과제를 만들며 공공 데이터가 많다는 것과, 내가 필요한 단위의 데이터가 있다는 것은 다른 문제라는 점을 알게 됐다. 원하는 세부 단위가 없다면 큰 통계에서 멈추는 대신 작은 단위의 규칙을 세우고, 다시 전체 통계에 맞게 보정할 수도 있다. 이 프로젝트는 그 과정을 알고리즘으로 실험한 결과였다.