본문 바로가기

Language/Python

Python에서 주소로 Tree만들기 법정동코드, 행정동코드 바꾸는 예제

728x90

개요


자료구조로 tree를 쓰는 이유는 탐색 속도를 빠르게 하기 위함입니다.

Tree를 쓰면 어떻게 빨라지는가 하면 내가 이미 타고온 반대쪽은 탐색을 하지 않아도 되기 때문에 속도가 O(log n)이 되는 것입니다.

이런 트리가 있다고 가정 해봅시다. 경기도 광주시 오포읍을 찾아가려면 트리의 경우는

'경기'로 가서

'광주시'를 찾고

'오포읍'을 찾으면 됩니다.

'서울'에 무슨 구가 있던지 무슨 동이 있던지 전혀 신경을 쓸 필요가 없습니다.

반대로 위와 같은 list가 있다고 생각 해봅시다. 대부분의 자료는 위와 같이 list형태로 되어 있는 경우가 많습니다. db에 주소가 들어가 있으면 위와 같이 들어 있을 것입니다.

 

데이터가 위와 같이 4개 밖에 없다면 '경기도 광주시 오포읍'을 금방 찾겠지만 실제로 db에서 뒤져야 하는 row수는 8000개가 넘습니다. 도로명 주소로 바뀌면서 탐색할 레코드가 훨씬 많아졌습니다.

 

그래서 이렇게 계층으로 되어있고 그 데이터를 자주 찾을때는 tree에서 찾는게 빠릅니다.

구현


실제로 찾고 싶은 것은 읍면동이 아니고 '행정동코드'(add_code)입니다.

시도, 시군구, 읍면동으로 주소를 찾는 로직을 만들 때 주소가 list에 들어있으면 한번 실행하는 속도가 O(n)입니다.

그런데 주소는 읍면동만 해도 8천개인데 가공해야 하는 row수가 100만개씩 되고 하면 속도가 아주 느릴 수 밖에 없습니다.

그래서 O(n)을 O(3)으로 줄이려고 아래 로직을 짰습니다.

 

아래 사이트에 들어가면 최신 법정동 행정동 매핑 파일을 받을 수 있습니다.

www.mois.go.kr/frt/bbs/type001/commonSelectBoardList.do?bbsId=BBSMSTR_000000000052

 

저는 '주민등록 주소 코드 변경 (2020. 8. 14. 시행 )'파일로 했습니다. jscode20200814(말소코드포함).zip [ 4.3 MB ] 이 파일을 받아서 KIKmix.20200814(말소코드포함) 에서 행정동 법정동 코드를 adm_code_law_code.csv로 바꾸어서 사용했습니다.

adm_code_law_code.csv
1.12MB

사용한 파일을 첨부합니다.

이런식으로 생겼습니다. adm_code는 행정동 코드이고 law_code는 법정동 코드 입니다.

 

import json

def make_tree(adm_law_codes):
    tre = {}
    for i in range(len(adm_law_codes)):
        spl = adm_law_codes[i].replace('\n','').split(',')
        # spl에서 2개 3개 나머지를 자른다.
        fst = spl[1][:2]
        snd = spl[1][2:5]
        trd = spl[1][5:]

        print(fst, snd, trd, type(fst))
        if tre.get(fst) == None:
            tre[fst] = {}
        if tre[fst].get(snd) == None:
            tre[fst][snd] = {}
        if tre[fst].get(snd).get(trd) == None:
            tre[fst][snd][trd] = spl[0]

    return tre

adm_law_codes = open('libs/adm_code_law_code.csv').readlines()[1:]
tre = make_tree(adm_law_codes)
open('tree_law_adm.json', 'w+').write(json.dumps(tre))

데이터 개수가 몇개 없으면 그냥 list 자료구조를 쓰면 되지만 바꿔야 할 주소는 여러개라서 tree로 짰습니다.

 

 

법정동코드 -> 행정동코드로 바꾸는 function예제

law_codes = json.loads(open('addr_codes.json').read())
dic = json.loads(open('tree_law_adm.json').read())
err_cnt = 0

def get_adm_code(law_code):
    try:
        f = law_code[:2]
        s = law_code[2:5]
        t = law_code[5:]
        adm_code = dic[f][s][t]
        return adm_code
    except Exception as e:
        print('error---', law_code)
        return None

for i in range(len(law_codes)):
    law_code = law_codes[i]
    adm_code = get_adm_code(law_code)
    if adm_code == None:
        err_cnt += 1
        print(law_code)
    else:
        print(adm_code)

print('err cnt:', err_cnt)

get_adm_code()에 law_code를 넣으면 adm_code를 return해줍니다.

728x90
블로그 주인장입니다. 원하시는 정보는 얻으셨나요? 이 포스트에서 추가로 필요한 정보가 있으시면 여기에 남겨주세요.