๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Project ESG+AI/[์‚ผ์ •KPMG]ESG ๋ฐ์ดํ„ฐ ํ™œ์šฉ ํ’€์Šคํ… ๊ฐœ๋ฐœ

42์ผ์ฐจ.

by GreenJin_S2 2025. 12. 10.

 

 

https://data.seoul.go.kr/dataList/316/S/2/datasetView.do

 

์—ด๋ฆฐ๋ฐ์ดํ„ฐ๊ด‘์žฅ ๋ฉ”์ธ

๋ฐ์ดํ„ฐ๋ถ„๋ฅ˜,๋ฐ์ดํ„ฐ๊ฒ€์ƒ‰,๋ฐ์ดํ„ฐํ™œ์šฉ

data.seoul.go.kr

 

 

 

 

 

 

 

 

 

 

pop=population

 

 

 

 

 

 

 

@ai.seoeunjin.com/mlservice/app/seoul_crime/seoul_data.py ์—ฌ๊ธฐ์—์„œ @seoul_data.py (31-42) ์ด๊ฒƒ์„ @seoul_data.py (10-12) ์ด ํ”ผ์ณ์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•ด์ค˜

 

 

@data ์ดํด๋”์˜ ์ ˆ๋Œ€๊ฒฝ๋กœ๋ฅผ _dname: str = '' # data path--> ์—ฌ๊ธฐ์— ์ƒ์ˆ˜๋กœ ์ €์žฅํ•ด์ค˜

str(Path(__file__).parent / "data")์ด๋Ÿฐ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ค˜

sname๋„ ๋ฐ”๊ฟ”์ค˜

 

 

 

import numpy as np
import pandas as pd
from pandas import DataFrame
import logging
from app.seoul_crime.seoul_data import SeoulData

logger = logging.getLogger(__name__)

class SeoulMethod(object):

    def __init__(self):
        self.dataset = SeoulData()

    def read_csv(self, fname: str) -> pd.DataFrame:
        return pd.read_csv(fname)

    def create_df(self, df: pd.DataFrame, label: str) -> pd.DataFrame:
        return df

 

์ด๋ถ€๋ถ„ ์ถ”๊ฐ€, import๋Š” method ์—์„œ ๊ฐ€์ ธ์˜ด

 

 
    def csv_to_df(self, fname: str) -> pd.DataFrame:
        return pd.read_csv(fname)

    def xlsx_to_df(self, fname: str) -> pd.DataFrame:
        return pd.read_csv(fname)

 

์ด๋ ‡๊ฒŒ ๋ณ€๊ฒฝ

 

 

xlsx ๋ถ€๋ถ„๋งŒ ๋Œ์–ด๋‹ค ๋†“๊ณ 

@seoul_method.py (17-19) ์ด๊ฒƒ์„ xlsxํŒŒ์ผ์„ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ๋ณ€๊ฒฝํ•ด์ค˜.

 

 

 

 

์„œ๋น„์Šค ํŒŒ์ผ

import sys
import pandas as pd
import numpy as np

class SeoulService(object):

    def __init__(self):
        self.the_method = SeoulMethod()

 

 

 

 

@api.seoeunjin.com/src/main/resources/application.yaml ์—ฌ๊ธฐ์— @mlservice ์—ฌ๊ธฐ๋กœ ์ด๋™ํ•˜๋Š” ํฌํŠธ๋ฅผ 9010์œผ๋กœ ์„ค์ •ํ•˜๊ณ , @application.yaml (39-44) ์ด ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•ด์„œ mlservice๋กœ ๊ฐ€๋Š” path๋ฅผ ์„ค์ •ํ•ด์ค˜

 

ใ…Žใ…Ž

์šฐ์„  ํƒ€์ดํƒ€๋‹‰ ๋ผ์šฐํ„ฐ ๋‚ด์šฉ-> ์„œ์šธ ๋ผ์šฐํ„ฐ์— ๋ณต์‚ฌํ•ด์„œ ์ฐพ๊ธฐ ๋ˆŒ๋Ÿฌ์„œ ์šฉ์–ด ๋ฐ”๊พธ๊ธฐ

 

ํฌ์ŠคํŠธ๋งจ์— send

http://localhost:8080/api/ml/seoul/preprocess

 

 

์ด ๊ฒฝ๋กœ๋ฅผ ๋ชป์ฐพ๋Š”๋ฐ, ๋„ˆ๊ฐ€ ์ˆ˜์ •ํ•ด์ค˜

 

 

        self.crime_rate_columns = ['์‚ด์ธ๊ฒ€๊ฑฐ์œจ', '๊ฐ•๋„๊ฒ€๊ฑฐ์œจ', '๊ฐ•๊ฐ„๊ฒ€๊ฑฐ์œจ', '์ ˆ๋„๊ฒ€๊ฑฐ์œจ', 'ํญ๋ ฅ๊ฒ€๊ฑฐ์œจ']
        self.crime_columns = ['์‚ด์ธ', '๊ฐ•๋„', '๊ฐ•๊ฐ„', '์ ˆ๋„', 'ํญ๋ ฅ']

 

x์— ์˜ฌ๋ ค์ฃผ์‹  ๋‚ด์šฉ ์ถ”๊ฐ€

 

 

๋ฉ”์†Œ๋“œ ํŒŒ์ผ์— ๋‚ด์šฉ ์ธ„๊ฐ€

 
    def df_merge(self, right: pd.DataFrame, left: pd.DataFrame, feature: str) -> pd.DataFrame:
        return pd.merge(right, left, on=feature)

 

์„œ๋น„์Šค ํŒŒ์ผ์— ๋‚ด์šฉ ์ถ”๊ฐ€

    cctv_pop = self.method.df_merge(cctv, pop, '๊ตฌ๋ณ„')

 

 

์ด๊ฑฐ ๊น”๊ธฐ

 

 

  1. ํŒŒ์ผ ๋ชฉ๋ก
     
  1. CCTV ๋ฐ์ดํ„ฐ
     
  1. Crime ๋ฐ์ดํ„ฐ
     
  1. Population ๋ฐ์ดํ„ฐ
     
  1. ์ „์ฒด ๋ฐ์ดํ„ฐ
     
  1. ๋จธ์ง€๋œ ๋ฐ์ดํ„ฐ
     

 

 

 


docker logs mlservice

ํ„ฐ๋ฏธ๋„์— ์•ˆ๋‚˜์˜ฌ๋•Œ!

 

 

 

์ด๋ถ€๋ถ„ ์„œ๋น„์Šค ํŒŒ์ผ์— ์ถ”๊ฐ€

            cctv = cctv.drop(['2013๋…„๋„ ์ด์ „', '2014๋…„', '2015๋…„', '2016๋…„'], axis=1, inplace=True)
            # pop ์ปฌ๋Ÿผ ํŽธ์ง‘
            # axis = 1 ๋ฐฉํ–ฅ์œผ๋กœ ์ž์น˜๊ตฌ์™€ ์ขŒ๋กœ๋ถ€ํ„ฐ 4๋ฒˆ์งธ ์ปฌ๋Ÿผ๋งŒ ๋‚จ๊ธฐ๊ณ  ๋ชจ๋‘ ์‚ญ์ œ
            # ์ปฌ๋Ÿผ๋ช… ํ™•์ธ ๋ฐ ์ค‘๋ณต ์ปฌ๋Ÿผ ์ฒดํฌ

 

 

@ai.seoeunjin.com/mlservice/app/seoul_crime/seoul_service.py @seoul_service.py (48-51) ์ด ์ฃผ์„๋Œ€๋กœ ์‹คํ–‰ํ•ด์ค˜

 

 

 


์นด์นด์˜ค ๋งต api key ๋ฐ›๋Š” ๋ฐฉ๋ฒ• ์•Œ๋ ค์ค˜

๊ตฌ๊ธ€์€ ์œ ๋ฃŒ๋ผ์„œ ์นด์นด์˜ค๋กœ ๊ฐ€๊ธฐ๋กœ ํ•จ!

 

 

๐Ÿ“ ์นด์นด์˜ค ์ง€๋„ API Key ๋ฐœ๊ธ‰ ๋ฐฉ๋ฒ•

โœ… 1. ์นด์นด์˜ค ๋””๋ฒจ๋กœํผ์Šค(Kakao Developers) ์ ‘์†

๐Ÿ”— https://developers.kakao.com

๋กœ๊ทธ์ธ → ์นด์นด์˜ค ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ


โœ… 2. ์ƒˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ

  1. ์˜ค๋ฅธ์ชฝ ์ƒ๋‹จ ๋‚ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
  2. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ถ”๊ฐ€ํ•˜๊ธฐ
  3. ์ด๋ฆ„ ์ž…๋ ฅ (์˜ˆ: "my map project")
  4. ์ €์žฅ

โœ… 3. ์•ฑ Key ํ™•์ธ

์•ฑ์„ ๋งŒ๋“ค๋ฉด ์ž๋™์œผ๋กœ ์•„๋ž˜ 4๊ฐ€์ง€ ํ‚ค๊ฐ€ ์ƒ์„ฑ๋ผ

  • JavaScript ํ‚ค (์›น์—์„œ ์ง€๋„ ๋„์šธ ๋•Œ ์‚ฌ์šฉ)
  • REST API ํ‚ค
  • Admin ํ‚ค
  • Native ํ‚ค (๋ชจ๋ฐ”์ผ ์•ฑ์šฉ)

๐Ÿ‘‰ ์ง€๋„ ๋„์šธ ๋•Œ๋Š” “JavaScript ํ‚ค”๋งŒ ํ•„์š”ํ•จ


โœ… 4. ํ”Œ๋žซํผ ๋“ฑ๋ก (์ค‘์š”!!)

์›น์—์„œ ์“ธ ๊ฑฐ๋ฉด ์‚ฌ์ดํŠธ ๋„๋ฉ”์ธ ๋“ฑ๋ก์€ ํ•„์ˆ˜์•ผ.

  1. ์ขŒ์ธก ๋ฉ”๋‰ด → ์•ฑ ์„ค์ • → ํ”Œ๋žซํผ
  2. ์›น(Web) ์„ ํƒ
  3. ์‚ฌ์ดํŠธ ๋„๋ฉ”์ธ ์ž…๋ ฅ

์˜ˆ์‹œ:

 
http://localhost:3000 http://127.0.0.1:5500 https://mywebsite.com

๐Ÿ“Œ ๋„๋ฉ”์ธ์€ ๋ฐ˜๋“œ์‹œ http/https ํฌํ•จํ•ด์„œ ๋“ฑ๋กํ•ด์•ผ ํ•จ


โœ… 5. ์นด์นด์˜ค ๋งต API ํ™œ์„ฑํ™” (ํ•„์š”ํ•œ ๊ฒฝ์šฐ)

๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ฃผ์†Œ ๊ฒ€์ƒ‰ ๋“ฑ์„ ์“ด๋‹ค๋ฉด:

  1. ๋‚ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ → API ์„œ๋น„์Šค → ๋กœ์ปฌ(Local)
  2. ํ™œ์„ฑํ™” ๋ฒ„ํŠผ ํด๋ฆญ

๐ŸŽ‰ ์ด์ œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ!

์›น์—์„œ ์ง€๋„ ๋„์šฐ๋Š” ๊ธฐ๋ณธ ์˜ˆ์‹œ

 
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=YOUR_JS_KEY"></script> <div id="map" style="width:100%;height:350px;"></div> <script> var mapContainer = document.getElementById('map'); var mapOption = { center: new kakao.maps.LatLng(37.5665, 126.9780), level: 3 }; var map = new kakao.maps.Map(mapContainer, mapOption); </script>

 

 

 

 

ํ™œ์„ฑํ™”

 

 

 


@ai.seoeunjin.com/mlservice/app/seoul_crime/kakao_map_singletone.py ์—ฌ๊ธฐ์— @ai.seoeunjin.com/mlservice/app/seoul_crime/google_map_singleton.py ์ด๊ฒƒ์„ ์ฐธ์กฐํ•ด์„œ, ์นด์นด์˜ค๋งต api์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•ด์ค˜

 

import googlemaps

class GoogleMapSingleton:
    _instance = None  # ์‹ฑ๊ธ€ํ„ด ์ธ์Šคํ„ด์Šค๋ฅผ ์ €์žฅํ•  ํด๋ž˜์Šค ๋ณ€์ˆ˜

    def __new__(cls):
        if cls._instance is None:  # ์ธ์Šคํ„ด์Šค๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
            cls._instance = super(GoogleMapSingleton, cls).__new__(cls)
            cls._instance._api_key = cls._instance._retrieve_api_key()  # API ํ‚ค ๊ฐ€์ ธ์˜ค๊ธฐ
            cls._instance._client = googlemaps.Client(key=cls._instance._api_key)  # Google Maps API ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
        return cls._instance  # ๊ธฐ์กด ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜

    def _retrieve_api_key(self):
        """API ํ‚ค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ"""
        return "..."  # ์‹ค์ œ API์—์„œ๋Š” ๋ณด์•ˆ๋œ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ€์ ธ์™€์•ผ ํ•จ

    def get_api_key(self):
        """์ €์žฅ๋œ API ํ‚ค ๋ฐ˜ํ™˜"""
        return self._api_key

    def geocode(self, address, language='ko'):
        """์ฃผ์†Œ๋ฅผ ์œ„๋„, ๊ฒฝ๋„๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ"""
        return self._client.geocode(address, language=language)

 

@ai.seoeunjin.com/mlservice/app/seoul_crime/seoul_service.py ์—์„œ KakaoMapSingleton์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด์ค˜

 

 

์นด์นด์˜ค ์•ฑ์—์„œ ํ‚ค ๋‹ค์šด๋ฐ›๊ณ  envํŒŒ์ผ์— ๋„ฃ๊ธฐ

 

@ai.seoeunjin.com/mlservice/app/seoul_crime/kakao_map_singletone.py ์—ฌ๊ธฐ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์นด์นด์˜ค REST APIํ‚ค๊ฐ’์„ ๋ฃจํŠธ์— ์žˆ๋Š” .envํŒŒ์ผ์—์„œ ์ฝ์–ด์˜ค๋„๋ก ์ฝ”๋”ฉํ•ด์ค˜

 

์žฌ๋นŒ๋“œ

docker compose build mlservice
docker compose up -d mlservice

 

 

์—๋Ÿฌ๋‚˜์„œ ํ•ด๊ฒฐํ•ด๋‹ฌ๋ผ๊ณ  ํ•จ

 

 

๋ฐฉ๋ฒ• 1: ์‹ค์‹œ๊ฐ„ ๋กœ๊ทธ ํ™•์ธ (๊ถŒ์žฅ)

ํ„ฐ๋ฏธ๋„์—์„œ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”:

 

์ด ๋ช…๋ น์–ด๋Š” ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋กœ๊ทธ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. Postman์—์„œ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ํ„ฐ๋ฏธ๋„์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๋ฐฉ๋ฒ• 2: ์ตœ๊ทผ ๋กœ๊ทธ ํ™•์ธ

 

๋ฐฉ๋ฒ• 3: VS Code Docker ํ™•์žฅ ์‚ฌ์šฉ

VS Code์˜ Docker ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปจํ…Œ์ด๋„ˆ ๋กœ๊ทธ๋ฅผ GUI์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

์ข€ ์œ„๋„์™€ ๊ฒฝ๋„๊ฐ™์ด ๋‚˜์˜ด

 

 

 

๊ฒฝ๋กœ ๊ตฌ์กฐ ์„ค๋ช…

  • /seoul/preprocess → ์ „์ฒ˜๋ฆฌ ์‹คํ–‰ ์—”๋“œํฌ์ธํŠธ
  • /seoul/files/{file_name} → ํŒŒ์ผ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์—”๋“œํฌ์ธํŠธ
  • {file_name}์€ cctv, crime, pop, cctv_pop ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค
  • preprocess๋Š” ์ง€์›๋˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…์ž…๋‹ˆ๋‹ค

์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  1. ์ „์ฒ˜๋ฆฌ ์‹คํ–‰:
     
  1. ์ „์ฒ˜๋ฆฌ๋œ Crime ๋ฐ์ดํ„ฐ ์กฐํšŒ:
     

Postman์—์„œ /api/ml/seoul/preprocess๋กœ ์š”์ฒญํ•˜์„ธ์š”.

 

 

save์— csvํŒŒ์ผ ๋งŒใ„ท๋“ค์–ด ์ ธ์•ผํ•จ.

๋‚ด์ผ ์™€์„œ ํ•ด๋ณด๊ธฐ!