54justin commited on
Commit
c22b7de
·
verified ·
1 Parent(s): 49f9284

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +252 -0
app.py ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 由 Copilot 生成
2
+ # 591租屋分析器 - 簡化版本(避免套件依賴問題)
3
+
4
+ import gradio as gr
5
+ import pandas as pd
6
+ import numpy as np
7
+ from datetime import datetime
8
+ import json
9
+
10
+ def generate_rental_data(sample_size):
11
+ """生成高雄市鼓山區租屋模擬資料"""
12
+ np.random.seed(42)
13
+
14
+ # 鼓山區常見地址
15
+ addresses = [
16
+ '高雄市鼓山區美術館路', '高雄市鼓山區博愛路', '高雄市鼓山區明誠路',
17
+ '高雄市鼓山區文信路', '高雄市鼓山區裕誠路', '高雄市鼓山區華榮路',
18
+ '高雄市鼓山區龍德路', '高雄市鼓山區鼓山路', '高雄市鼓山區九如路',
19
+ '高雄市鼓山區綠川街', '高雄市鼓山區美術東路', '高雄市鼓山區青海路'
20
+ ]
21
+
22
+ # 房屋特色關鍵字
23
+ features = [
24
+ '近捷運', '電梯大樓', '採光佳', '通風良好', '停車位', '管理完善',
25
+ '生活機能佳', '近美術館', '學區', '安靜社區', '新裝潢', '家具家電'
26
+ ]
27
+
28
+ data = []
29
+ for i in range(int(sample_size)):
30
+ # 基本資料
31
+ area = np.random.normal(32, 6) # 平均32坪,標準差6
32
+ area = max(25, min(45, area)) # 限制在25-45坪之間
33
+
34
+ # 租金計算(基於坪數和隨機因子)
35
+ base_price = area * np.random.normal(800, 100) # 每坪約800元
36
+ location_factor = np.random.uniform(0.8, 1.3) # 地段因子
37
+ price = int(base_price * location_factor)
38
+ price = max(18000, min(45000, price)) # 限制在合理範圍
39
+
40
+ # 選擇地址和特色
41
+ address = np.random.choice(addresses) + f"{i+1}號"
42
+ selected_features = np.random.choice(features,
43
+ size=np.random.randint(2, 5),
44
+ replace=False)
45
+
46
+ data.append({
47
+ 'title': f'鼓山區2房電梯大樓-{i+1}',
48
+ 'price': price,
49
+ 'area': round(area, 1),
50
+ 'price_per_ping': round(price / area, 0),
51
+ 'address': address,
52
+ 'features': ', '.join(selected_features),
53
+ 'type': '整層住家',
54
+ 'layout': '2房1廳1衛',
55
+ 'building_type': '電梯大樓'
56
+ })
57
+
58
+ return pd.DataFrame(data)
59
+
60
+ def analyze_rental_data(sample_size, analysis_type):
61
+ """執行租屋資料分析"""
62
+ try:
63
+ # 生成資料
64
+ df = generate_rental_data(sample_size)
65
+
66
+ if df.empty:
67
+ return "❌ 無法生成資料", None, None, pd.DataFrame()
68
+
69
+ # 基本統計
70
+ stats = {
71
+ 'total_count': len(df),
72
+ 'avg_price': df['price'].mean(),
73
+ 'median_price': df['price'].median(),
74
+ 'std_price': df['price'].std(),
75
+ 'min_price': df['price'].min(),
76
+ 'max_price': df['price'].max(),
77
+ 'avg_area': df['area'].mean(),
78
+ 'avg_price_per_ping': df['price_per_ping'].mean()
79
+ }
80
+
81
+ # 生成分析報告
82
+ report = f"""
83
+ # 🏠 高雄市鼓山區租屋市場分析報告
84
+
85
+ **分析時間**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
86
+ **資料來源**: 591租屋網模擬資料
87
+ **分析條件**: 2房整層電梯大樓
88
+
89
+ ## 📊 市場概況
90
+
91
+ ### 基本統計
92
+ - **總物件數**: {stats['total_count']} 筆
93
+ - **平均租金**: NT$ {stats['avg_price']:,.0f} 元/月
94
+ - **租金中位數**: NT$ {stats['median_price']:,.0f} 元/月
95
+ - **租金標準差**: NT$ {stats['std_price']:,.0f} 元
96
+ - **租金區間**: NT$ {stats['min_price']:,.0f} ~ {stats['max_price']:,.0f} 元
97
+
98
+ ### 坪數分析
99
+ - **平均坪數**: {stats['avg_area']:.1f} 坪
100
+ - **平均每坪租金**: NT$ {stats['avg_price_per_ping']:,.0f} 元/坪
101
+
102
+ ### 市場洞察
103
+ """
104
+
105
+ # 根據分析類型添加額外洞察
106
+ if stats['avg_price'] > stats['median_price']:
107
+ report += "- 租金分布偏右,存在高價物件拉高平均值\n"
108
+
109
+ if stats['avg_price_per_ping'] > 900:
110
+ report += "- 每坪租金偏高,顯示該區域生活機能佳\n"
111
+ elif stats['avg_price_per_ping'] < 700:
112
+ report += "- 每坪租金相對親民,適合小資族群\n"
113
+
114
+ report += f"\n**由 GitHub Copilot 生成** ✨"
115
+
116
+ # 生成統計表格
117
+ price_stats, price_dist = create_price_distribution_chart(df, analysis_type)
118
+ area_stats, price_per_ping_stats = create_area_analysis_chart(df, analysis_type)
119
+
120
+ # 準備資料表格
121
+ display_df = df[['title', 'price', 'area', 'price_per_ping', 'address', 'features']].copy()
122
+ display_df.columns = ['物件名稱', '租金(元)', '坪數', '每坪租金', '地址', '特色']
123
+
124
+ return report, price_stats, area_stats, price_dist, price_per_ping_stats, display_df
125
+
126
+ except Exception as e:
127
+ error_msg = f"❌ 分析過程發生錯誤: {str(e)}\n\n請稍後再試或聯繫���術支援。"
128
+ empty_df = pd.DataFrame()
129
+ return error_msg, empty_df, empty_df, empty_df, empty_df, empty_df
130
+
131
+ def create_price_distribution_chart(df, analysis_type):
132
+ """創建租金分布統計表格"""
133
+ # 創建租金分布統計
134
+ price_stats = {
135
+ '統計項目': ['最低租金', '最高租金', '平均租金', '中位數租金', '標準差'],
136
+ '數值 (元)': [
137
+ f"{df['price'].min():,}",
138
+ f"{df['price'].max():,}",
139
+ f"{df['price'].mean():.0f}",
140
+ f"{df['price'].median():.0f}",
141
+ f"{df['price'].std():.0f}"
142
+ ]
143
+ }
144
+
145
+ # 租金區間分布
146
+ df_temp = df.copy()
147
+ df_temp['price_range'] = pd.cut(df_temp['price'],
148
+ bins=[0, 20000, 25000, 30000, 35000, float('inf')],
149
+ labels=['<2萬', '2-2.5萬', '2.5-3萬', '3-3.5萬', '>3.5萬'])
150
+
151
+ range_counts = df_temp['price_range'].value_counts().sort_index()
152
+
153
+ distribution_data = {
154
+ '租金區間': range_counts.index.tolist(),
155
+ '物件數量': range_counts.values.tolist(),
156
+ '占比 (%)': [f"{(count/len(df)*100):.1f}%" for count in range_counts.values]
157
+ }
158
+
159
+ return pd.DataFrame(price_stats), pd.DataFrame(distribution_data)
160
+
161
+ def create_area_analysis_chart(df, analysis_type):
162
+ """創建坪數分析統計表格"""
163
+ # 坪數統計
164
+ area_stats = {
165
+ '統計項目': ['最小坪數', '最大坪數', '平均坪數', '中位數坪數'],
166
+ '數值 (坪)': [
167
+ f"{df['area'].min():.1f}",
168
+ f"{df['area'].max():.1f}",
169
+ f"{df['area'].mean():.1f}",
170
+ f"{df['area'].median():.1f}"
171
+ ]
172
+ }
173
+
174
+ # 每坪租金統計
175
+ price_per_ping_stats = {
176
+ '統計項目': ['最低每坪租金', '最高每坪租金', '平均每坪租金', '中位數每坪租金'],
177
+ '數值 (元/坪)': [
178
+ f"{df['price_per_ping'].min():.0f}",
179
+ f"{df['price_per_ping'].max():.0f}",
180
+ f"{df['price_per_ping'].mean():.0f}",
181
+ f"{df['price_per_ping'].median():.0f}"
182
+ ]
183
+ }
184
+
185
+ return pd.DataFrame(area_stats), pd.DataFrame(price_per_ping_stats)
186
+
187
+ # 創建 Gradio 介面
188
+ with gr.Blocks(title="🏠 591租屋分析器", theme=gr.themes.Soft()) as demo:
189
+ gr.Markdown("""
190
+ # 🏠 591租屋分析器 - 高雄市鼓山區
191
+
192
+ 專門分析高雄市鼓山區2房整層電梯大樓租屋市場,提供詳細的統計分析和視覺化圖表。
193
+
194
+ **目標條件**:高雄市鼓山區 | 2房 | 整層住家 | 電梯大樓
195
+ """)
196
+
197
+ with gr.Row():
198
+ with gr.Column(scale=1):
199
+ sample_size = gr.Slider(
200
+ minimum=20, maximum=200, value=80, step=10,
201
+ label="📊 分析樣本數",
202
+ info="選擇要生成的租屋物件數量"
203
+ )
204
+
205
+ analysis_type = gr.Radio(
206
+ choices=["基本分析", "進階分析", "詳細分析"],
207
+ value="基本分析",
208
+ label="🔍 分析類型",
209
+ info="選擇分析的詳細程度"
210
+ )
211
+
212
+ analyze_btn = gr.Button("🚀 開始分析", variant="primary", size="lg")
213
+
214
+ with gr.Column(scale=2):
215
+ with gr.Tab("📋 分析報告"):
216
+ report_output = gr.Markdown(label="分析報告")
217
+
218
+ with gr.Tab("📊 統計分析"):
219
+ with gr.Row():
220
+ with gr.Column():
221
+ price_stats_output = gr.Dataframe(label="租金統計")
222
+ price_dist_output = gr.Dataframe(label="租金區間分布")
223
+ with gr.Column():
224
+ area_stats_output = gr.Dataframe(label="坪數統計")
225
+ price_per_ping_output = gr.Dataframe(label="每坪租金統計")
226
+
227
+ with gr.Tab("📁 詳細資料"):
228
+ data_output = gr.Dataframe(
229
+ label="租屋物件詳細資料",
230
+ interactive=True,
231
+ wrap=True
232
+ )
233
+
234
+ # 設定按鈕事件
235
+ analyze_btn.click(
236
+ fn=analyze_rental_data,
237
+ inputs=[sample_size, analysis_type],
238
+ outputs=[report_output, price_stats_output, area_stats_output,
239
+ price_dist_output, price_per_ping_output, data_output]
240
+ )
241
+
242
+ gr.Markdown("""
243
+ ---
244
+ **📍 分析範圍**: 高雄市鼓山區 (美術館、愛河、駁二藝術特區周邊)
245
+ **🏠 物件類型**: 2房1廳1衛、整層住家、電梯大樓
246
+ **📊 資料說明**: 使用模擬資料展示分析功能,實際部署可串接真實API
247
+
248
+ *由 GitHub Copilot 生成* ✨
249
+ """)
250
+
251
+ if __name__ == "__main__":
252
+ demo.launch()