Skip to content

Commit 2423679

Browse files
committed
Initial commit after excluding Google Drive files
1 parent 99af102 commit 2423679

File tree

2 files changed

+63
-30
lines changed

2 files changed

+63
-30
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33
*.gdoc
44
*.gsheet
55
drive/
6+
*.gdoc
7+
*.gsheet
8+
drive/

main.py

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,33 @@
2222

2323
merged_model = pd.read_pickle("merged_model.pkl")
2424

25-
# '?' -> '·' 변환
26-
merged_model['행정동_코드_명'] = merged_model['행정동_코드_명'].str.replace('?', '·', regex=False)
25+
# '?' -> '.' 변환
26+
merged_model['행정동_코드_명'] = merged_model['행정동_코드_명'].str.replace('?', '.', regex=False)
2727

2828
# 수치 포맷 함수들
2929
def format_ratio(x):
3030
return f"{x:.5f}"
3131

3232
def format_money_mw(x):
33+
"""
34+
금액(x)을 만원 단위로만 반환
35+
ex) 36000000 → '3600'
36+
"""
3337
return str(int(round(x / 10000)))
3438

3539
def format_income_mw(x):
40+
"""
41+
월 평균 소득(x)을 만원 단위로 반환
42+
ex) 3600000 → '360'
43+
"""
3644
return str(int(round(x / 10000)))
3745

38-
def generate_result_template(행정동명):
46+
def generate_result_template(merged_model, 행정동명):
3947
등급_텍스트 = {0: '하', 1: '중', 2: '상'}
4048
등급_info = {
4149
'상': {'desc': '매우 높음', 'precision': '77%', 'recommendations': ['카페', '헬스장', '미용실']},
4250
'중': {'desc': '보통', 'precision': '62%', 'recommendations': ['편의점', '분식집', '세탁소']},
43-
'하': {'desc': '낮음', 'precision': '69%', 'recommendations': ['중고매장', 'PC방', '호프집']},
51+
'하': {'desc': '낮음', 'precision': '69%', 'recommendations': ['중고매장', 'PC방', '호프집']}
4452
}
4553

4654
filtered = merged_model[merged_model['행정동_코드_명'] == 행정동명].copy()
@@ -70,56 +78,76 @@ def generate_result_template(행정동명):
7078
여_ratio = filtered['여성_유동인구_비율'].mean()
7179
주성별 = '남성' if 남_ratio >= 여_ratio else '여성'
7280

73-
age_pop_cols = [
74-
'연령대_10_유동인구_수', '연령대_20_유동인구_수',
75-
'연령대_30_유동인구_수', '연령대_40_유동인구_수',
76-
'연령대_50_유동인구_수', '연령대_60_이상_유동인구_수'
77-
]
7881
연령대별비율_cols = [f"{col}_비율" for col in age_pop_cols]
7982
avg_age_ratios = filtered[연령대별비율_cols].mean()
80-
주연령대 = avg_age_ratios.idxmax().replace('_비율', '').replace('연령대_', '').replace('_유동인구_수', '') + '대'
83+
주연령대 = avg_age_ratios.idxmax().replace('_비율', '')
8184

8285
peak_time = filtered['최대_시간대_이름'].mode().iloc[0]
8386

8487
reasons = []
88+
# 1) 유동인구 변화율 비교
8589
if 지역_avg_flow > 전국_avg_flow:
86-
reasons.append(f"유동인구 변화율이 전국 평균보다 높습니다 ({format_ratio(지역_avg_flow)} > {format_ratio(전국_avg_flow)}).")
90+
reasons.append(
91+
f"유동인구 변화율이 전국 평균보다 높습니다 ({format_ratio(지역_avg_flow)} > {format_ratio(전국_avg_flow)})."
92+
)
8793
else:
88-
reasons.append(f"유동인구 변화율이 전국 평균보다 낮습니다 ({format_ratio(지역_avg_flow)} < {format_ratio(전국_avg_flow)}).")
89-
94+
reasons.append(
95+
f"유동인구 변화율이 전국 평균보다 낮습니다 ({format_ratio(지역_avg_flow)} < {format_ratio(전국_avg_flow)})."
96+
)
97+
# 2) 전년 동기 대비 유동인구 변화율 “추세” 템플릿
9098
if np.isclose(지역_avg_yoy_pop, 전국_avg_yoy_pop):
9199
reasons.append("전년 동기 대비 유동인구 변화가 전국 평균과 유사한 수준입니다.")
92100
elif 지역_avg_yoy_pop > 전국_avg_yoy_pop:
93101
reasons.append("전년 동기 대비 유동인구가 전국 평균보다 증가 추세를 보입니다.")
94102
else:
95103
reasons.append("전년 동기 대비 유동인구가 전국 평균보다 감소 추세를 보입니다.")
96-
104+
# 3) 현재 매출 비교
97105
if 지역_avg_sales > 전국_avg_sales:
98-
reasons.append(f"현재(당월) 평균 매출이 전국 평균보다 높습니다 ({format_money_mw(지역_avg_sales)}만 원 > {format_money_mw(전국_avg_sales)}만 원).")
106+
reasons.append(
107+
f"현재(당월) 평균 매출이 전국 평균보다 높습니다 ({format_money_mw(지역_avg_sales)}만 원 > {format_money_mw(전국_avg_sales)}만 원)."
108+
)
99109
else:
100-
reasons.append(f"현재(당월) 평균 매출이 전국 평균보다 낮습니다 ({format_money_mw(지역_avg_sales)}만 원 < {format_money_mw(전국_avg_sales)}만 원).")
101-
110+
reasons.append(
111+
f"현재(당월) 평균 매출이 전국 평균보다 낮습니다 ({format_money_mw(지역_avg_sales)}만 원 < {format_money_mw(전국_avg_sales)}만 원)."
112+
)
113+
# 4) 전년 동기 대비 매출 변화율 “추세” 템플릿
102114
if np.isclose(지역_avg_yoy_sales, 전국_avg_yoy_sales):
103115
reasons.append("전년 동기 대비 매출 변화가 전국 평균과 유사한 수준입니다.")
104116
elif 지역_avg_yoy_sales > 전국_avg_yoy_sales:
105117
reasons.append("전년 동기 대비 매출이 전국 평균보다 상승 추세를 보입니다.")
106118
else:
107119
reasons.append("전년 동기 대비 매출이 전국 평균보다 하락 추세를 보입니다.")
108-
120+
# 5) 평균 소득 비교 (단위: 만원)
109121
if 지역_avg_income > 전국_avg_income:
110-
reasons.append(f"월 평균 소득이 전국 평균보다 높습니다 ({format_income_mw(지역_avg_income)}만 원 > {format_income_mw(전국_avg_income)}만 원).")
122+
reasons.append(
123+
f"월 평균 소득이 전국 평균보다 높습니다 ({format_income_mw(지역_avg_income)}만 원 > {format_income_mw(전국_avg_income)}만 원)."
124+
)
111125
else:
112-
reasons.append(f"월 평균 소득이 전국 평균보다 낮습니다 ({format_income_mw(지역_avg_income)}만 원 < {format_income_mw(전국_avg_income)}만 원).")
113-
126+
reasons.append(
127+
f"월 평균 소득이 전국 평균보다 낮습니다 ({format_income_mw(지역_avg_income)}만 원 < {format_income_mw(전국_avg_income)}만 원)."
128+
)
129+
# 6) 데이터 건수 비교
114130
전국_avg_count = 전국.groupby('행정동_코드_명').size().mean()
115131
if 지역_count > 전국_avg_count:
116-
reasons.append(f"이 지역 데이터 건수가 평균보다 많아 예측 신뢰도가 높습니다 ({지역_count}개 > {전국_avg_count:.1f}개).")
132+
reasons.append(
133+
f"이 지역 데이터 건수가 평균보다 많아 예측 신뢰도가 높습니다 ({지역_count}개 > {전국_avg_count:.1f}개)."
134+
)
117135
else:
118-
reasons.append(f"이 지역 데이터 건수가 평균보다 적어 데이터가 제한적일 수 있습니다 ({지역_count}개 < {전국_avg_count:.1f}개).")
119-
120-
업종별_avg_future = filtered.groupby('서비스_업종_코드_명')['향후_평균_매출'].mean().sort_values(ascending=False)
136+
reasons.append(
137+
f"이 지역 데이터 건수가 평균보다 적어 데이터가 제한적일 수 있습니다 ({지역_count}개 < {전국_avg_count:.1f}개)."
138+
)
139+
140+
# 동적 Top3 업종 추천
141+
업종별_avg_future = (
142+
filtered
143+
.groupby('서비스_업종_코드_명')['향후_평균_매출']
144+
.mean()
145+
.sort_values(ascending=False)
146+
)
121147
top3_업종 = 업종별_avg_future.head(3).index.tolist()
122-
fixed_reco = info['recommendations']
148+
149+
# 하드코딩된 등급별 추천업종
150+
fixed_reco = 등급_info[top_grade]['recommendations']
123151

124152
output = f"""
125153
🔍 '{행정동명}' 상권 분석 결과
@@ -137,7 +165,7 @@ def generate_result_template(행정동명):
137165
output += f"""
138166
🔹 주요 고객층 및 피크 시간대:
139167
- 주요 고객 성별: {주성별}
140-
- 주요 고객 연령대: {주연령대}
168+
- 주요 고객 연령대: {주연령대.replace('연령대_', '').replace('_유동인구_수', '')}
141169
- 피크 매출 시간대: {peak_time}
142170
143171
✅ '{행정동명}' 지역 동적 추천 업종 Top 3:
@@ -146,13 +174,15 @@ def generate_result_template(행정동명):
146174
3. {top3_업종[2]}
147175
148176
🔹 '{top_grade}' 등급에 속할 때 추천 업종:
149-
1. {fixed_reco[0]}
150-
2. {fixed_reco[1]}
151-
3. {fixed_reco[2]}
152177
"""
178+
for idx, 업종 in enumerate(fixed_reco, start=1):
179+
output += f"{idx}. {업종}
180+
"
153181

154182
return output
155183

184+
185+
156186
@app.get("/")
157187
def health_check():
158188
return {"status": "ok", "message": "상권 분석 API가 실행 중입니다."}

0 commit comments

Comments
 (0)