Rooobert commited on
Commit
a33fe85
·
verified ·
1 Parent(s): 933be95

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -152
app.py CHANGED
@@ -33,49 +33,24 @@ class SurveyMappings:
33
  class SurveyAnalyzer:
34
  """📊 問卷分析類"""
35
 
36
- def __init__(self, df):
37
  self.mappings = SurveyMappings()
38
-
39
- # Method to find the closest matching column
40
- def find_matching_column(possible_columns):
41
- for col in possible_columns:
42
- # Try different variations of potential column names
43
- variations = [
44
- col,
45
- col.replace(':', ''),
46
- col.replace('.', ''),
47
- col.strip()
48
- ]
49
- for var in variations:
50
- if var in df.columns:
51
- return var
52
- return None
53
-
54
- # Predefined column templates
55
- column_templates = [
56
- ('多元課程與活動', ['示範場域提供多元的數位課程與活動', '1: 示範場域提供多元的數位課程與活動']),
57
- ('生活應用有幫助', ['示範場域的數位課程與活動對我的生活應用有幫助', '2.示範場域的數位課程與活動對我的生活應用有幫助']),
58
- ('服務人員親切', ['示範場域的服務人員親切有禮貌', '3: 示範場域的服務人員親切有禮貌']),
59
- ('空間設備友善', ['示範場域的服務空間與數位設備友善方便', '4.示範場域的服務空間與數位設備友善方便']),
60
- ('獲得需要協助', ['在示範場域可以獲得需要的協助', '5.在示範場域可以獲得需要的協助']),
61
- ('整體服務滿意', ['對於示範場域的服務感到滿意', '6.對於示範場域的服務感到滿意'])
62
  ]
63
-
64
- # Find matching columns
65
- self.satisfaction_short_names = []
66
- self.satisfaction_columns = []
67
-
68
- for short_name, column_options in column_templates:
69
- matched_col = None
70
- for col_option in column_options:
71
- matched_col = find_matching_column([col_option])
72
- if matched_col:
73
- self.satisfaction_columns.append(matched_col)
74
- self.satisfaction_short_names.append(short_name)
75
- break
76
-
77
- if not matched_col:
78
- st.warning(f"Could not find column for {short_name}")
79
 
80
  def calculate_age(self, birth_year_column):
81
  """🔢 計算年齡(從民國年到實際年齡)"""
@@ -96,48 +71,14 @@ class SurveyAnalyzer:
96
  def generate_report(self, df: pd.DataFrame) -> Dict[str, Any]:
97
  """📝 生成問卷調查報告"""
98
  # 計算年齡
99
- age_column = '2.出生年(民國__年)'
100
- # 找到最接近的年齡欄位
101
- possible_age_columns = [
102
- '2.出生年(民國__年)',
103
- '出生年',
104
- '出生年(民國__年)'
105
- ]
106
- for col in possible_age_columns:
107
- if col in df.columns:
108
- age_column = col
109
- break
110
-
111
- ages = self.calculate_age(df[age_column])
112
 
113
  # 取得教育程度分布(帶計數單位)
114
- education_column = '3.教育程度'
115
- # 找到最接近的教育程度欄位
116
- possible_education_columns = [
117
- '3.教育程度',
118
- '教育程度'
119
- ]
120
- for col in possible_education_columns:
121
- if col in df.columns:
122
- education_column = col
123
- break
124
-
125
- education_counts = df[education_column].value_counts().to_dict()
126
  education_with_counts = {k: f"{v}人" for k, v in education_counts.items()}
127
 
128
  # 性別分布(帶計數單位)
129
- gender_column = '1. 性別'
130
- # 找到最接近的性別欄位
131
- possible_gender_columns = [
132
- '1. 性別',
133
- '性別'
134
- ]
135
- for col in possible_gender_columns:
136
- if col in df.columns:
137
- gender_column = col
138
- break
139
-
140
- gender_counts = df[gender_column].value_counts().to_dict()
141
  gender_with_counts = {k: f"{v}人" for k, v in gender_counts.items()}
142
 
143
  # 計算每個滿意度項目的平均分數和標準差
@@ -209,38 +150,13 @@ class SurveyAnalyzer:
209
  """🟠 性別分佈圓餅圖(使用藍色和紅色)"""
210
  # 過濾數據
211
  filtered_df = df.copy()
212
-
213
- # 場域篩選
214
- venue_column = '場域名稱'
215
- possible_venue_columns = ['場域名稱', 'venue']
216
- for col in possible_venue_columns:
217
- if col in filtered_df.columns:
218
- venue_column = col
219
- break
220
-
221
  if venues and '全部' not in venues:
222
- filtered_df = filtered_df[filtered_df[venue_column].isin(venues)]
223
-
224
- # 月份篩選
225
- month_column = '月份'
226
- possible_month_columns = ['月份', 'month']
227
- for col in possible_month_columns:
228
- if col in filtered_df.columns:
229
- month_column = col
230
- break
231
-
232
  if month and month != '全部':
233
- filtered_df = filtered_df[filtered_df[month_column] == month]
234
-
235
- # 性別欄位
236
- gender_column = '1. 性別'
237
- possible_gender_columns = ['1. 性別', '性別']
238
- for col in possible_gender_columns:
239
- if col in filtered_df.columns:
240
- gender_column = col
241
- break
242
-
243
- gender_counts = filtered_df[gender_column].value_counts().reset_index()
244
  gender_counts.columns = ['性別', '人數']
245
 
246
  # 計算百分比
@@ -273,60 +189,73 @@ class SurveyAnalyzer:
273
 
274
  # 🎨 Streamlit UI
275
  def main():
276
- # 設置頁面配置
277
  st.set_page_config(
278
- page_title="114年度樂齡學習數位示範體驗場域 服務滿意度調查分析報告",
279
- page_icon="📊",
280
  layout="wide"
281
  )
282
 
283
- # 添加標題和子標題
284
  st.markdown("""
285
- # 114年度樂齡學習數位示範體驗場域 服務滿意度調查分析報告
286
- ## 全面理解樂齡學習者數位服務體驗
 
 
 
 
 
287
 
288
- 本報告提供全面的問卷調查分析與視覺化圖表,深入剖析樂齡學習者參與數位示範場域服務的滿意情形。
289
- 透過詳細的統計分析和互動式圖表,我們旨在呈現樂齡學習者的服務體驗和需求洞察。
290
 
291
- ### 報告製作單位
292
- **國立中正大學高齡教育研究中心專案管理團隊**
293
- """)
294
-
295
- # 分隔線
296
- st.markdown("---")
297
 
298
- # 上傳 CSV 檔案
299
- uploaded_file = st.file_uploader("上傳 CSV 檔案", type=['csv'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
 
301
- # 初始化數據和分析器
302
- df = None
303
- analyzer = None
 
304
 
305
- # 檢查是否有上傳檔案
306
- if uploaded_file is not None:
307
- try:
308
- df = pd.read_csv(uploaded_file, encoding='utf-8')
309
- st.success("CSV 檔案上傳成功!")
310
- except Exception as e:
311
- st.error(f"無法讀取檔案:{e}")
312
- return
 
 
 
 
313
 
314
- # 如果沒有上傳檔案,提供使用預設數據的選項
315
- if df is None:
316
- if st.button('使用預設範例數據'):
317
- df = read_google_sheet(sheet_id, gid)
318
-
319
- if df is None:
320
- st.error("無法讀取預設數據,請上傳 CSV 檔案")
321
- return
322
 
323
- # 如果有數據,則進行分析
324
- if df is not None:
325
- analyzer = SurveyAnalyzer(df)
326
 
327
- # 新增場域和月份篩選器
328
- st.sidebar.header("🔍 數據篩選")
329
-
330
- # 場域篩選
331
- venue_column = '場域名稱'
332
- possible_venue_columns = ['場域名稱', 'venue']
 
33
  class SurveyAnalyzer:
34
  """📊 問卷分析類"""
35
 
36
+ def __init__(self):
37
  self.mappings = SurveyMappings()
38
+ self.satisfaction_columns = [
39
+ '1. 示範場域提供多元的數位課程與活動',
40
+ '2.示範場域的數位課程與活動對我的生活應用有幫助',
41
+ '3. 示範場域的服務人員親切有禮貌',
42
+ '4.示範場域的服務空間與數位設備友善方便',
43
+ '5.在示範場域可以獲得需要的協助',
44
+ '6.對於示範場域的服務感到滿意'
45
+ ]
46
+ self.satisfaction_short_names = [
47
+ '多元課程與活動',
48
+ '生活應用有幫助',
49
+ '服務人員親切',
50
+ '空間設備友善',
51
+ '獲得需要協助',
52
+ '整體服務滿意'
 
 
 
 
 
 
 
 
 
53
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
  def calculate_age(self, birth_year_column):
56
  """🔢 計算年齡(從民國年到實際年齡)"""
 
71
  def generate_report(self, df: pd.DataFrame) -> Dict[str, Any]:
72
  """📝 生成問卷調查報告"""
73
  # 計算年齡
74
+ ages = self.calculate_age(df['2.出生年(民國__年)'])
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
  # 取得教育程度分布(帶計數單位)
77
+ education_counts = df['3.教育程度'].value_counts().to_dict()
 
 
 
 
 
 
 
 
 
 
 
78
  education_with_counts = {k: f"{v}人" for k, v in education_counts.items()}
79
 
80
  # 性別分布(帶計數單位)
81
+ gender_counts = df['1. 性別'].value_counts().to_dict()
 
 
 
 
 
 
 
 
 
 
 
82
  gender_with_counts = {k: f"{v}人" for k, v in gender_counts.items()}
83
 
84
  # 計算每個滿意度項目的平均分數和標準差
 
150
  """🟠 性別分佈圓餅圖(使用藍色和紅色)"""
151
  # 過濾數據
152
  filtered_df = df.copy()
 
 
 
 
 
 
 
 
 
153
  if venues and '全部' not in venues:
154
+ filtered_df = filtered_df[filtered_df['場域名稱'].isin(venues)]
 
 
 
 
 
 
 
 
 
155
  if month and month != '全部':
156
+ # 假設有一個月份欄位,如果沒有請調整
157
+ filtered_df = filtered_df[filtered_df['月份'] == month]
158
+
159
+ gender_counts = filtered_df['1. 性別'].value_counts().reset_index()
 
 
 
 
 
 
 
160
  gender_counts.columns = ['性別', '人數']
161
 
162
  # 計算百分比
 
189
 
190
  # 🎨 Streamlit UI
191
  def main():
 
192
  st.set_page_config(
193
+ page_title="樂齡學習數位示範體驗場域 服務滿意度調查",
194
+ page_icon="📊",
195
  layout="wide"
196
  )
197
 
 
198
  st.markdown("""
199
+ # 📊 114年度樂齡學習數位示範體驗場域
200
+ ## 服務滿意度調查分析報告
201
+
202
+ *國立中正大學高齡教育研究中心專案管理團隊 精心製作*
203
+
204
+ 本報告提供全面的問卷調查分析與視覺化圖表,深入剖析樂齡學習者參與數位示範場域服務的滿意情形。透過精細的數據分析,我們旨在瞭解高齡學習者的服務體驗,並為未來數位學習環境的優化提供寶貴洞見。
205
+ """, unsafe_allow_html=True)
206
 
207
+ # 讀取數據
208
+ df = read_google_sheet(sheet_id, gid)
209
 
210
+ if df is not None:
211
+ analyzer = SurveyAnalyzer()
 
 
 
 
212
 
213
+ # 新增場域和月份篩選器
214
+ st.sidebar.header("🔍 數據篩選")
215
+
216
+ # 假設數據有「場域名稱」欄位,如果名稱不同請調整
217
+ if '場域名稱' in df.columns:
218
+ venues = ['全部'] + sorted(df['場域名稱'].unique().tolist())
219
+ selected_venues = st.sidebar.multiselect("選擇場域", venues, default=['全部'])
220
+ else:
221
+ # 如果沒有場域欄位,創建10個虛擬場域供選擇
222
+ venues = ['全部'] + [f'場域{i+1}' for i in range(10)]
223
+ selected_venues = st.sidebar.multiselect("選擇場域", venues, default=['全部'])
224
+
225
+ # 假設數據有「月份」欄位,如果沒有請調整
226
+ if '月份' in df.columns:
227
+ months = ['全部'] + sorted(df['月份'].unique().tolist())
228
+ selected_month = st.sidebar.selectbox("選擇月份", months)
229
+ else:
230
+ # 如果沒有月份欄位,可以創建虛擬月份選項
231
+ months = ['全部'] + [f'{i+1}月' for i in range(12)]
232
+ selected_month = st.sidebar.selectbox("選擇月份", months)
233
 
234
+ # 📌 基本統計數據
235
+ st.sidebar.header("📌 選擇數據分析")
236
+ selected_analysis = st.sidebar.radio("選擇要查看的��析",
237
+ ["📋 問卷統計報告", "📊 滿意度統計", "🟠 性別分佈"])
238
 
239
+ if selected_analysis == "📋 問卷統計報告":
240
+ st.header("📋 問卷統計報告")
241
+ report = analyzer.generate_report(df)
242
+ for category, stats in report.items():
243
+ with st.expander(f"🔍 {category}", expanded=True):
244
+ for key, value in stats.items():
245
+ if key == '各項滿意度':
246
+ st.write(f"**{key}:**")
247
+ for item, item_stats in value.items():
248
+ st.write(f" - **{item}**: {', '.join([f'{k}: {v}' for k, v in item_stats.items()])}")
249
+ else:
250
+ st.write(f"**{key}**: {value}")
251
 
252
+ elif selected_analysis == "📊 滿意度統計":
253
+ st.header("📊 滿意度統計")
254
+ analyzer.plot_satisfaction_scores(df)
 
 
 
 
 
255
 
256
+ elif selected_analysis == "🟠 性別分佈":
257
+ st.header("🟠 性別分佈")
258
+ analyzer.plot_gender_distribution(df, selected_venues, selected_month)
259
 
260
+ if __name__ == "__main__":
261
+ main()