이전에 구성한 DB구성 모듈로 하여금 아주대 반경 약 3km안의 대중시설들의 정보를 모두 카카오맵 API를 활용하여 얻었다. 약 5400개의 시설이 Database Table에 저장되었다.
브라우저에서 입력을 받은 프론트엔드단에서 데이터가 서버로 전달된다. 해당 데이터는 클라이언트가 선택한 기준 주소와 선택한 시설을 받는 것으로 가정하고 주소변수와 시설변수를 가정한다.
여러 쿼리를 만들 것을 가정하여 쿼리 클래스를 제작했다. 기본적으로 mysql_connector에서 사용될 기본정보로 초기화 변수를 구성했다.
# 조건에 해당하는 데이터프레임 반환
# ----------- 예시 조건 ------------
# 클라이언트로부터 주소를 받음
# 클라이언트가 스타벅스, 맥도날드, 올리브영, 크린토피아를 선택함
import pandas as pd
import mysql.connector
from dis_min import haversine, change_min
from change import get_lat_lng_from_address
class QuerySemose:
def __init__(self,
host="호스트",
user="DB사용자 이름",
password="비밀번호",
database="데이터 베이스 이름"):
self.host = host
self.user = user
self.password = password
self.database = database
self.tabel_name = "places" # 테이블 이름
def get_info_condition(self, client_address, client_condition):
# MySQL 서버에 연결
connection = mysql.connector.connect(
host=self.host,
user=self.user,
password=self.password,
database=self.database
)
# SQL 쿼리를 사용하여 데이터를 데이터프레임으로 가져옵니다.
# 동적 쿼리 생성
query_conditions = " OR ".join([f"place_name LIKE '%{item}%'" for item in client_condition])
query = f"SELECT * FROM {self.tabel_name} WHERE {query_conditions}"
# 거리 계산해서 distance에 반영
df = pd.read_sql(query, connection)
# 클라이언트로부터 입력받은 주소 위경도로 변환
lat, lng = get_lat_lng_from_address(client_address)
# 거리 계산
df["distance"] = df.apply(lambda x: change_min(lat, lng, x["y"], x["x"]), axis=1)
df = df.sort_values(by=["distance"])
# 거리가 가까운 순으로 5개만 반환
return df
test = QuerySemose()
test_df = test.get_info_condition("클라이언트로 받은 주소", ["스타벅스", "맥도날드", "올리브영", "크린토피아"])
print(test_df[['place_name','distance']])
쿼리는 리스트안에 들어있는 시설 수에 따라 문법이 변화하므로 그에 맞게 리스트에 있는 모든 시설을 포함하도록 동적으로 쿼리변수를 만들었다.
이후에 mysql.connector를 활용하여 조건에 맞는 행들만 DB에서 추출하여 dataframe을 만든다.
DB에 있는 시설 현황
- 프로젝트의 스코프인 아주대 주변 3km반경에 대한 시설물들을 모두 카카오맵 API를 활용하여 DB에 추가했으며 시각화결과는 다음과 같다.
1차적으로 DB에서 조건 리스트에 해당하는 시설들을 모두 데이터프레임으로 불러왔다.
기준이 되는 주소의 좌표를 찾기 위해 GoogleMap API를 활용했다.
import requests
def get_lat_lng_from_address(address, api_key="발급받은 API key"):
base_url = "https://maps.googleapis.com/maps/api/geocode/json"
params = {
"address": address,
"key": api_key,
}
response = requests.get(base_url, params=params)
data = response.json()
if data['status'] == 'OK':
location = data['results'][0]['geometry']['location']
lat = location['lat']
lng = location['lng']
return lat, lng
else:
return None
예로 "경기도 수원시 영통구 월드컵로 206 팔달관"
이라는 주소를 넣으면 위, 경도를 반환해준다. DB에 있는 시설에 대한 위, 경도는 모두 확보되어 있기에 이를 pandas의 apply를 통해 주어진 주소에 대해 모두 거리를 측정한다. 프로젝트의 특성상 거리는 도보시간(분)으로 환산해서 직관성을 확보하기 위해 일반적으로 위,경도로 하여금 거리를 측정하는 haversine모듈 다음 추가적으로 시간으로 변환하는 과정을 거쳐준다.
import math
def haversine(lat1, lon1, lat2, lon2):
# 지구의 반지름 (킬로미터)
radius = 6371
# 위도 및 경도를 라디안으로 변환
lat1 = math.radians(lat1)
lon1 = math.radians(lon1)
lat2 = math.radians(lat2)
lon2 = math.radians(lon2)
# Haversine 공식을 사용하여 두 지점 간의 거리 계산
dlon = lon2 - lon1
dlat = lat2 - lat1
a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
distance = radius * c
return distance
def change_min(lat1, lon1, lat2, lon2): # 도보 걸음걸이 속도 = 67m/min
distance = haversine(lat1, lon1, lat2, lon2)
min_ = distance * 1000 / 67
return min_
이렇게 주소를 기준으로 위도와 경도를 활용하여 None으로 꽉찬 df의 distance칼럼을 채워준다.그렇게되면 다음과 같은 조건(특정 주소)에 해당하는 가장 가까운 시설들의 정보를 얻을 수 있다.(distance기준 정렬필요)
이 정보중에 15분안에 해당하는 세권정의에 해당하는 데이터로 하여금 2차적인 계산후에 점수를 뽑아내도록 할 것이다.