상세 컨텐츠

본문 제목

[Algorithm] 쓰레기 배출 시뮬레이션 (1)

Algorithm

by 몽골리안 파프리카 2023. 1. 9. 15:29

본문

728x90

 소위 '빌라촌'의 고질적 문제는 주차와 쓰레기 문제 등이 있다. 골목길을 넓히고 유휴부지를 충분히 확보하면 해결될 문제들이지만, 현실적으로 쉽지 않다. 동시에 꼭 해결되어야 할 문제이기도 하다.

 해서, 지난 학기 도시재생 수업 중 '사당 4동 도시재생 프로젝트 과제' 를 통해 사당 4동의 쓰레기 문제를 해결하기 위한 방안으로 강구해낸 방법이 쓰레기 수거 방식의 변화였다.

 우리나라의 쓰레기 수거 체계는 크게 3가지로 나눌 수 있다. 문전수거 방식 / 거점형 수거 방식 / 혼합형 수거 방식 이 그것이다.

 먼저 문전수거 방식은 말 그대로 각자 집 앞에 쓰레기를 배출하는 방식이다. 배출 요일과 시간이 정해져 있어서 해당 시점에 쓰레기를 배출해야 한다. 대부분 빌라촌에서 사용되는 방식이며, 규칙만 존재할 뿐 관리인이 없으니 주민 갈등이 자주 일어나는 방식이기도 하다. 단순히 문 앞에 쓰레기를 모아두는 방식이기 때문에 미관상 좋지 않고 여름철 악취 문제도 있다.

 거점형 수거 방식은 특정한 쓰레기 배출 장소, 즉, 거점을 두고 그 곳에 쓰레기를 배출하는 방식이다. 대부분 아파트에서 차용하는 방식이며, 보통은 관리인이 있기 때문에 부정적 외부효과가 비교적 덜하다. 하지만 거점을 설치할 공간이나 관리 인력이 필요하다는 점에서 아파트처럼 공간 확보가 용이하지 않은 주거 환경에는 적용하기 힘들다는 단점이 있다.

 혼합형 수거 방식은 문전수거와 거점형 수거 방식이 합쳐진 방식이다.

 

 본 프로젝트의 핵심은 기존 문전수거 방식이었던 쓰레기 수거 체계를 거점형 수거 방식으로 바꾸는 데 있다. 기존 체계에서 벗어나 새로운 체계를 도입하는 만큼 여러 경제적, 사회적 요인들을 고려해 득실을 따져야 한다. 쓰레기 배출 시뮬레이션 알고리즘 역시 이러한 맥락에서 만들어졌다. 한정된 공간과 예산을 가장 효율적으로 사용하기 위해서는 거점 별 쓰레기 수용량을 최적화해야 한다. 시뮬레이션을 통해 각각의 거점이 수용해야 할 쓰레기 용량이 어느정도 인지 가늠해 본다.

 

 연구 모델은 크게 두 단계를 거친다.

1. 데이터 정제
2. 시뮬레이션

 데이터 정제 단계에서는 사당 4동의 연속지적도와 건축물대장(표제부)을 결합하여 필지 별 세대 수를 추출한다. 그리고 필지 별 거점을 할당한다.

 시뮬레이션 단계에서는 각 세대를 행위자로 설정한 후 쓰레기 배출 규칙을 부여해 거점 별 쓰레기 수용량을 확인한다.

 

 작성한 코드를 보며 자세한 설명을 한다.

#%% Library
import numpy as np
import random
import pandas as pd
import geopandas as gpd
from shapely.geometry import Point

from tqdm import tqdm
import warnings
import matplotlib.pyplot as plt
import seaborn as sns
import shapefile
import json
from mapboxgl.viz import *
from mapboxgl.utils import *

#%% Directory
load_dir = (r'C:\Users\PC\Desktop\주영준\진행중인 프로젝트\New Point\001 Load Directory')
save_dir = (r'C:\Users\PC\Desktop\주영준\진행중인 프로젝트\New Point\003 Save Directory')

warnings.filterwarnings(action='ignore')

 

서울시 연속지적도와 센서스 행정동 경계 shp 파일을 이용해 사당 4동의 연속 지적도를 추출한 후, 표제부와 결합한다.

# 사당4동 연속지적도 생성
sd = gpd.read_file(load_dir + '/haengjeongdong/Z_SOP_BND_ADM_DONG_PG.shp', encoding='cp949')
sd = sd[sd['ADM_DR_NM'] == '사당4동']
sd = sd[['ADM_DR_NM', 'geometry']]

jijuk = gpd.read_file(load_dir + '/jijuk_dongjak/LSMD_CONT_LDREG_11590.shp', encoding='cp949')
jijuk = gpd.GeoDataFrame(jijuk, geometry='geometry', crs=5186)
jijuk = jijuk.to_crs(5181)


sd = gpd.overlay(jijuk, sd, how='intersection')
sd = sd[['pnu', 'jibun', 'geometry']]
sd.columns = ['PNU', 'JIBUN', 'geometry']
sd = sd.reset_index(drop=True)
sd.plot()

sd.to_file(save_dir + '/sadang4/sadang4.shp', encoding='cp949')


# 연속지적도 표제부 결합
file_columns = pd.read_excel(load_dir + '/filcolumns.xlsx')
use_cols = ['관리_건축물대장_PK', '시군구_코드', '법정동_코드', '대지_구분_코드', '번', '지', '주_용도_코드_명', '기타_용도', '세대_수(세대)', '가구_수(가구)']

pjb = pd.read_csv(load_dir + '/pjb/mart_djy_03.txt', sep='|', names=file_columns['mart_djy_03(pjb)'].dropna(), header=None, usecols=use_cols, dtype=str, encoding='cp949')
pjb.isna().sum()

pjb = pjb.dropna(axis=0, subset=['대지_구분_코드'])
pjb['대지_구분_코드'] = pjb['대지_구분_코드'].astype(int)
pjb['대지_구분_코드'] += 1
pjb['대지_구분_코드'] = pjb['대지_구분_코드'].astype(str)

pjb['PNU'] = pjb['시군구_코드'] + pjb['법정동_코드'] + pjb['대지_구분_코드'] + pjb['번'] + pjb['지']

pjb.columns = ['PPK', '시군구_코드', '법정동_코드', '대지_구분_코드', '번', '지', 'USE_CODE_0_NM', 'USE_CODE_1_NM', 'SD', 'GG', 'PNU']
pjb = pjb[['PNU', 'PPK', 'USE_CODE_0', 'USE_CODE_1', 'SD', 'GG']]

del file_columns, use_cols


sd = pd.merge(sd, pjb, on='PNU', how='left')

 

결합 후 데이터를 정제한다.

# 데이터 정제
sd = sd[sd['JIBUN'].str.contains('대') == True]               # '대'만 남기기

apt = sd[sd['USE_CODE_1_NM'].str.contains('아파트') == True]['PNU'].unique().tolist()
for a in apt:
    sd = sd.drop(sd[sd['PNU'] == a].index.tolist(), axis=0)

del a, apt

sd = sd.dropna()
sd = sd.reset_index(drop=True)


sd['SD'] = sd['SD'].astype(int)
sd['GG'] = sd['GG'].astype(int)

sd['SD'] = sd['SD'] + sd['GG']
sd['GG'] = 0

sd['SD'].loc[(sd['USE_CODE_0'] == '단독주택') & (sd['USE_CODE_1'].str.contains('다중') == True) & (sd['SD'] == 0)] = 1

sd['GG'].loc[(sd['USE_CODE_0'].str.contains('근린') == True) | (sd['USE_CODE_1'].str.contains('근린|점포') == True)] = 1
sd['GG'].loc[(sd['USE_CODE_0'] != '단독주택') & (sd['USE_CODE_0'] != '공동주택')] = 1


sd.to_file(save_dir + '/sadang4/sadang4.shp', encoding='cp949')

 결측치가 발생하는 경우는 하나의 건축물이 두 개 필지에 걸쳐 있는 경우였다. 해당 건축물의 건축물 대장상 필지고유 번호는 둘 중 한 필지에만 존재했기 때문에 다른 한 필지는 결측치가 발생한 것이다. 결측치는 제거했다.

* 참고) 건축법 시행령 제 3조 1항 1, 2 목

 지목이 '대' 가 아닌 필지 (도, 산, 천 ...) 에서는 쓰레기 배출이 이루어지지 않는다고 판단하여 제거했다.

 아파트의 경우 이미 거점이 존재하므로 연구 대상에서 제외했다. 이 과정에서 아파트와 필지고유번호를 공유하는 경비실, 기계실, 주차장 등 시설을 함께 제거했다.

 

 이후 필지 별로 세대를 부여했다. (여기서 행위자가 되는 세대는 건축물 대장 상 세대와 다르다. 세대, 가구, 호를 통칭하는 말이다. 따로 부를 말이 없어서 이렇게 부른다.) 건축물 대장 상에서는 

가구 : 단독주택
세대 : 공동주택
호     : 그 외

로 구분하고 있다. 거의 대부분 결측치 없이 가구와 세대가 잘 mapping 되어 있었지만, 일부 데이터에 문제가 있었다. 단독주택 중 다중주택과 근린생활시설이 그것이었다.

 다중주택은 단독 주택으로 분류되어 가구 수 1 로 표기되어 있지만, 실제로는 여러 사람이 거주하는 건축물이다. 호 수에 제한이 없어서 표제부만 봐서는 한 건축물 안에 몇 명이 사는 지 알 수 없고, 분류 상 단독주택이기 때문에 전유부에도 호 수가 기재되어 있지 않다. 하는 수 없이 가구 수 1로 처리했다.

 근린생활시설의 경우 세대와 가구 모두 결측치로 나오는 경우가 많았다. 전유부 데이터를 결합해서 가게 수를 세어보려고 했지만, 확인이 불가했다.

 이외에도 건축물대장상 단독주택이고, 다중주택도 아닌데 세대와 가구가 모두 0 인 경우도 있었다. 확인 결과 공사 중인 필지였다.

 

 이렇게 기본적 데이터 정제를 마쳤다. 세대 별 거점 부여 및 시뮬레이션 알고리즘은 다음 글에서 살펴본다.

관련글 더보기