안녕하세요
어느 날 문득 서로 떨어져 있는 친구들과 약속 장소를 정하는 일이 생각보다 어렵다는 것을 깨달았습니다.
각자 출발하는 위치도 다르고, 대중교통을 타는지 차를 타는지에 따라 걸리는 시간도 제각각이기 때문입니다.
그래서 이런 불편함을 직접 해결해보고자 meet-in-the-middle↗ 이라는 약속 장소 추천 서비스를 개발하게 되었습니다.
처음에는 단순히 지도에서 핀을 찍어 중간 지점을 찾으면 될 줄 알았습니다.
하지만 실제로는 참여자 모두의 이동 시간과 목적, 취향을 동시에 만족시켜야 하는 복잡한 문제였습니다.
이번 시리즈에는 이 서비스 개발 경험을 바탕으로, 약속 장소 추천을 머신러닝 문제로 재정의하는 방법을 공유해 보려고 합니다.
특히 실무에서 강력한 성능을 내는
XGBoost
알고리즘을 도입하기 전, 목표 변수와 평가 지표를 어떻게 세워야 하는지 차근차근 설명해 드리겠습니다.
서비스 초기에는 지도 API를 활용해 사용자들의 출발지 좌표를 모아 평균을 내고, 그 중심에서 가까운 장소를 보여주는 방식을 사용했습니다.
이 방식은 코드를 짜기 쉽고 결과도 아주 빠르게 나옵니다.
하지만 서비스를 운영하며 사용자들(지인)의 피드백을 받아보니 명확한 한계들이 보이기 시작했습니다.
지도상의 직선거리는 가깝지만, 막상 대중교통을 타면 빙 돌아가야 하는 경우가 많습니다.
환승 횟수나 배차 간격에 따라 실제 도착 예상 시간은 거리와 완전히 다르게 나타납니다.
이런 교통 상황을 무시하고 거리만 평균을 내어 추천하면, 누군가는 10분 만에 도착하고 누군가는 1시간이 걸리는 불공평한 상황이 발생합니다.
오랜만에 만나는 친구들과의 저녁 식사와, 스터디 모임을 위한 카페 탐색은 장소를 고르는 기준이 다릅니다.
스터디를 하는데 홍대를 추천하고, 친구들과 저녁 식사에 삼성역을 추천하면 만족하기 어렵겠죠..
규칙 기반 방식은 이렇게 상황마다 달라지는 사용자의 숨은 의도를 점수에 반영하기가 매우 까다롭습니다.
결국 화면에 장소가 추천되더라도 사용자의 마음에 들지 않아 선택받지 못하는 경우가 늘어났습니다.
추가적으로, 실제 라벨을 계산하는 로직은 ml/label_builder.py 파일에 구현을 진행합니다.
ml/label_builder.py
# 사용자 행동 데이터를 종합하여 머신러닝 학습용 타깃 점수를 계산합니다.def build_target_score(user_action): # 화면에 아예 노출되지 않은 장소는 학습할 의미가 없으므로 제외합니다. if user_action["is_exposed"] == 0: return None # 행동의 깊이에 따라 가중치를 다르게 부여합니다. (확정에 가까울수록 높은 점수) click_score = 0.2 if user_action["is_clicked"] == 1 else 0.0 vote_score = 0.3 if user_action["is_voted"] == 1 else 0.0 final_score = 0.4 if user_action["is_final_selected"] == 1 else 0.0 # 5점 만점의 만족도 별점을 0에서 0.1 사이의 추가 보너스 점수로 변환합니다. rating = user_action.get("rating", 0) feedback_score = (rating / 5.0) * 0.1 # 모든 점수를 합산하여 최종 점수를 반환합니다. return click_score + vote_score + final_score + feedback_score
위 함수는 한 줄의 사용자 행동 로그에서 target_score를 만들어냅니다.
예를 들어 클릭과 투표가 모두 있었던 후보는 0.2 + 0.3으로 0.5점이 됩니다.
최종 확정과 별점 5점까지 받은 후보는 0.2 + 0.4 + 0.1로 0.7점이 됩니다.
👨💻
이렇게 만들어진 target_score는 0에서 1 사이의 연속적인 값으로, 랭킹 모델이 학습할 수 있는 훌륭한 라벨이 됩니다.
우선, 샘플 입력 데이터는 JSONL 형식으로 준비해 두었습니다.
JSONL은 한 줄에 JSON 하나가 들어있는 형식이라서 로그 데이터를 다룰 때 많이 씁니다.
직접 서비스를 만들어보며 느낀 점은, 추천 시스템을 도입할 때 무작정 좋은 모델을 쓰는 것보다 문제를 정확하게 정의하는 것이 훨씬 중요하다는 사실이었습니다.
단순한 좌표 계산이나 분류 문제가 아닌 랭킹 문제로 접근하고, 사용자의 실제 행동 데이터를 바탕으로 정교한 라벨을 만들어야 합니다.
이러한 기반 공사를 튼튼히 해두면, 추후 모델이 서비스에 투입되었을 때 훨씬 더 안정적이고 만족스러운 약속 장소를 추천해 줍니다.
다음 2편에서는 오늘 정의한 목표를 달성하기 위해, 실제 추천 데이터를 수집하고 데이터베이스 스키마를 설계했던 구축 과정을 자세히 알아보겠습니다.