Update pages/3_๐_์ ๊ท_๊ณต์ฐ์ฅ_์ถ์ฒ_ํ์ด์ง.py
Browse files
pages/3_๐_์ ๊ท_๊ณต์ฐ์ฅ_์ถ์ฒ_ํ์ด์ง.py
CHANGED
|
@@ -3,7 +3,11 @@ import pandas as pd
|
|
| 3 |
import numpy as np
|
| 4 |
import re
|
| 5 |
import ast
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
from utils.recommend_utils import recommend_venues
|
| 9 |
|
|
@@ -24,71 +28,102 @@ def create_perf_vector(title, cast, genre, price, search_score):
|
|
| 24 |
genre_score = genre_score_map.get(genre, 0.5)
|
| 25 |
price_value = extract_first_ticket_price(price)
|
| 26 |
price_norm = price_value / 200000 if price_value else 0
|
| 27 |
-
|
| 28 |
return [round(price_norm, 3), round(genre_score, 2), round(search_score, 3)]
|
| 29 |
|
| 30 |
-
#
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
try:
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
| 3 |
import numpy as np
|
| 4 |
import re
|
| 5 |
import ast
|
| 6 |
+
|
| 7 |
+
import folium
|
| 8 |
+
from streamlit_folium import st_folium
|
| 9 |
+
from geopy.geocoders import Nominatim
|
| 10 |
+
from geopy.extra.rate_limiter import RateLimiter
|
| 11 |
|
| 12 |
from utils.recommend_utils import recommend_venues
|
| 13 |
|
|
|
|
| 28 |
genre_score = genre_score_map.get(genre, 0.5)
|
| 29 |
price_value = extract_first_ticket_price(price)
|
| 30 |
price_norm = price_value / 200000 if price_value else 0
|
|
|
|
| 31 |
return [round(price_norm, 3), round(genre_score, 2), round(search_score, 3)]
|
| 32 |
|
| 33 |
+
# ๐ข ๋ฉ์ธ ์ฑ
|
| 34 |
+
st.set_page_config(layout="wide")
|
| 35 |
+
st.title("๐ ์ ๊ท ๋ดํ ๊ณต์ฐ ์ ๋ณด ์
๋ ฅ โ ๊ณต์ฐ์ฅ ์ถ์ฒ")
|
| 36 |
+
|
| 37 |
+
st.subheader("1๏ธโฃ ๊ณต์ฐ ์ ๋ณด ์
๋ ฅ")
|
| 38 |
+
title = st.text_input("๊ณต์ฐ ์ ๋ชฉ")
|
| 39 |
+
cast = st.text_input("์ถ์ฐ์ง (์ฒซ ๋ช
๋ง ์
๋ ฅํด๋ ๋จ)")
|
| 40 |
+
genre = st.selectbox("์ฅ๋ฅด ์ ํ", list(genre_score_map.keys()))
|
| 41 |
+
price = st.text_input("๋ํ ํฐ์ผ๊ฐ๊ฒฉ (์: 99,000์ ๋๋ ์ซ์๋ง ์
๋ ฅ)")
|
| 42 |
+
|
| 43 |
+
st.subheader("2๏ธโฃ ๊ฒ์๋ ์์ค ์ ํ")
|
| 44 |
+
search_category = st.selectbox("๐ ๋ด์ค ๊ฒ์๋ ๋ฑ๊ธ", ["๋ฎ์", "๋ณดํต", "๋์", "๋งค์ฐ ๋์"])
|
| 45 |
+
search_score_map = {
|
| 46 |
+
"๋ฎ์": 0.2,
|
| 47 |
+
"๋ณดํต": 0.5,
|
| 48 |
+
"๋์": 0.8,
|
| 49 |
+
"๋งค์ฐ ๋์": 1.0
|
| 50 |
+
}
|
| 51 |
+
search_score = search_score_map[search_category]
|
| 52 |
+
|
| 53 |
+
st.subheader("3๏ธโฃ ์ ์ฌ๋ ๊ฐ์ค์น ์ค์ ")
|
| 54 |
+
w1 = st.slider("ํฐ์ผ๊ฐ ๊ฐ์ค์น", 0.0, 1.0, 0.5)
|
| 55 |
+
w2 = st.slider("์ฅ๋ฅด ๊ฐ์ค์น", 0.0, 1.0, 0.3)
|
| 56 |
+
w3 = st.slider("๊ฒ์๋ ๊ฐ์ค์น", 0.0, 1.0, 0.2)
|
| 57 |
+
alpha = st.slider("๐ฏ ์ข
ํฉ์ ์ฌ๋์์ ๋ฒกํฐ ์ ์ฌ๋ ๋น์ค (ฮฑ)", 0.0, 1.0, 0.7)
|
| 58 |
+
|
| 59 |
+
# ๐ ์คํ
|
| 60 |
+
if st.button("๐ ๋ฒกํฐ ์์ฑ ๋ฐ ์ถ์ฒ ์คํ"):
|
| 61 |
+
if not title or not genre or not price:
|
| 62 |
+
st.error("๊ณต์ฐ ์ ๋ชฉ, ์ฅ๋ฅด, ๊ฐ๊ฒฉ์ ํ์ ์
๋ ฅ์
๋๋ค.")
|
| 63 |
+
st.stop()
|
| 64 |
+
|
| 65 |
+
perf_vector = create_perf_vector(title, cast, genre, price, search_score)
|
| 66 |
+
st.success(f"๐ฏ ์์ฑ๋ ๊ณต์ฐ ๋ฒกํฐ: {perf_vector}")
|
| 67 |
+
|
| 68 |
+
# โ
๋ฐ์ดํฐ ๋ก๋
|
| 69 |
+
try:
|
| 70 |
+
df = pd.read_excel("data/์ต์ข
.xlsx")
|
| 71 |
+
venue_df = pd.read_excel("data/๊ณต์ฐ์์คDB.xlsx")
|
| 72 |
+
except Exception as e:
|
| 73 |
+
st.error(f"โ ๋ฐ์ดํฐ ํ์ผ ๋ก๋ ์ค๋ฅ: {e}")
|
| 74 |
+
st.stop()
|
| 75 |
+
|
| 76 |
+
df = df[df["๊ณต์ฐ์ฅ๋ฒกํฐ"].notna()].copy()
|
| 77 |
+
try:
|
| 78 |
+
df["๊ณต์ฐ์ฅ๋ฒกํฐ"] = df["๊ณต์ฐ์ฅ๋ฒกํฐ"].apply(ast.literal_eval)
|
| 79 |
+
except Exception as e:
|
| 80 |
+
st.error(f"โ ๊ณต์ฐ์ฅ ๋ฒกํฐ ํ์ฑ ์ค๋ฅ: {e}")
|
| 81 |
+
st.stop()
|
| 82 |
+
|
| 83 |
+
df = df.merge(venue_df, on="๊ณต์ฐ์์คID", how="left")
|
| 84 |
+
|
| 85 |
+
# โ
๊ณต์ฐ์์คID ์ค๋ณต ์ ๊ฑฐ
|
| 86 |
+
df = df.drop_duplicates(subset="๊ณต์ฐ์์คID")
|
| 87 |
+
|
| 88 |
+
# โ
์ถ์ฒ ์ํ
|
| 89 |
+
results = recommend_venues(perf_vector, df, weights=[w1, w2, w3], alpha=alpha)
|
| 90 |
+
top_results = results.sort_values("์ข
ํฉ์ ์ฌ๋", ascending=False).head(10)
|
| 91 |
+
|
| 92 |
+
# โ
ํ ์ถ๋ ฅ
|
| 93 |
+
st.subheader("โ
์ถ์ฒ ๊ณต์ฐ์ฅ ๋ฆฌ์คํธ (์ค๋ณต ์ ๊ฑฐ๋ ์์ 10๊ณณ)")
|
| 94 |
+
st.dataframe(top_results[[
|
| 95 |
+
"๊ณต์ฐ์์ค๋ช
", "๊ณต์ฐ์์คID", "์ ์ฌ๋", "๊ฐ์์์ ์ฌ๋", "์ข
ํฉ์ ์ฌ๋", "๊ฐ์ ์",
|
| 96 |
+
"๋ ์คํ ๋", "์นดํ", "ํธ์์ ",
|
| 97 |
+
"์ฅ์ ์์ค-์ฃผ์ฐจ์ฅ", "์ฅ์ ์์ค-ํ์ฅ๏ฟฝ๏ฟฝ๏ฟฝ", "์ฅ์ ์์ค-๊ฒฝ์ฌ๋ก", "์ฅ์ ์์ค-์๋ฆฌ๋ฒ ์ดํฐ", "์ฃผ์"
|
| 98 |
+
]])
|
| 99 |
+
|
| 100 |
+
# โ
์ง๋ ์๊ฐํ
|
| 101 |
+
st.subheader("๐บ๏ธ ์ถ์ฒ ๊ณต์ฐ์ฅ ์์น ์ง๋")
|
| 102 |
+
geolocator = Nominatim(user_agent="kopis_map_app")
|
| 103 |
+
geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)
|
| 104 |
+
|
| 105 |
+
address_coords = {}
|
| 106 |
+
for addr in top_results["์ฃผ์"].dropna().unique():
|
| 107 |
try:
|
| 108 |
+
loc = geocode(addr)
|
| 109 |
+
if loc:
|
| 110 |
+
address_coords[addr] = (loc.latitude, loc.longitude)
|
| 111 |
+
except:
|
| 112 |
+
continue
|
| 113 |
+
|
| 114 |
+
map_center = [37.5665, 126.9780]
|
| 115 |
+
m = folium.Map(location=map_center, zoom_start=11)
|
| 116 |
+
|
| 117 |
+
for _, row in top_results.iterrows():
|
| 118 |
+
addr = row["์ฃผ์"]
|
| 119 |
+
name = row["๊ณต์ฐ์์ค๋ช
"]
|
| 120 |
+
latlon = address_coords.get(addr)
|
| 121 |
+
if latlon:
|
| 122 |
+
folium.Marker(
|
| 123 |
+
location=latlon,
|
| 124 |
+
popup=f"{name}<br>{addr}",
|
| 125 |
+
tooltip=name,
|
| 126 |
+
icon=folium.Icon(color='blue', icon='info-sign')
|
| 127 |
+
).add_to(m)
|
| 128 |
+
|
| 129 |
+
st_folium(m, width=900, height=500)
|