Tom commited on
Commit
8219718
·
1 Parent(s): 2b3c8c9
Files changed (1) hide show
  1. app.py +72 -268
app.py CHANGED
@@ -3,15 +3,14 @@ import numpy as np
3
  import matplotlib.pyplot as plt
4
  import seaborn as sns
5
  import warnings
6
- import io
7
- import base64
8
  from sklearn.model_selection import train_test_split
9
  from sklearn.ensemble import RandomForestClassifier
10
  from sklearn.metrics import classification_report
11
  from sklearn.preprocessing import StandardScaler
12
  from sklearn.cluster import KMeans
13
  from sklearn.decomposition import PCA
14
- import gradio as gr
15
 
16
  # Suppress specific FutureWarnings
17
  warnings.filterwarnings("ignore", category=FutureWarning)
@@ -39,19 +38,6 @@ def clean_data(df):
39
 
40
  df = df.drop(columns=['nsn'], errors='ignore')
41
 
42
- category_cols = [
43
- 'gender', 'ethnicity', 'year_level', 'contributing_primary_school',
44
- 'year_11_english_teacher', 'year_11_maths_teacher', 'year_12_english_teacher',
45
- 'year_12_maths_teacher', 'form_teacher', 'leaving_date', 'primary_language',
46
- 'first_language', 'secondary_language', 'term_1_intervention',
47
- 'term_2_intervention', 'term_3_intervention', 'term_4_intervention',
48
- 'major_life_event', 'learning_difficulty', 'pastoral_care_incident',
49
- 'pastoral_care_action_taken', 'pastoral_care_follow_up'
50
- ]
51
- for col in category_cols:
52
- if col in df.columns:
53
- df[col] = df[col].astype('category')
54
-
55
  if 'ncea_results' in df.columns:
56
  ncea_results = []
57
  for idx, row in df.iterrows():
@@ -68,11 +54,6 @@ def clean_data(df):
68
  else:
69
  df['Total Credits'] = 0
70
 
71
- if 'pastoral_care_follow_up' in df.columns:
72
- df['action_effective'] = df['pastoral_care_follow_up'].apply(
73
- lambda x: 'Effective' if 'resolved' in str(x).lower() else 'Not Effective'
74
- )
75
-
76
  df['credit_threshold'] = df['year_level'].apply(lambda x: 80 if x == 'Year 11' else 60)
77
  df['credit_achievement_rate'] = df['Total Credits'] / df['credit_threshold']
78
 
@@ -106,264 +87,87 @@ def identify_at_risk_students(df):
106
  model.fit(X_train, y_train)
107
  y_pred = model.predict(X_test)
108
 
109
- report = classification_report(y_test, y_pred)
110
 
111
  importances = model.feature_importances_
112
  feature_names = features.columns
113
  feature_importance_df = pd.DataFrame({'Feature': feature_names, 'Importance': importances})
114
  feature_importance_df = feature_importance_df.sort_values(by='Importance', ascending=False)
115
 
116
- graphs = []
117
- tables = {}
118
-
119
- tables['classification_report'] = report
120
- tables['feature_importance'] = feature_importance_df.head(10).to_string()
121
-
122
- if feature_importance_df['Importance'].sum() > 0:
123
- plt.figure(figsize=(12, 6))
124
- sns.barplot(data=feature_importance_df.head(10), x='Importance', y='Feature', palette='viridis')
125
- plt.title('Top 10 Important Features for Predicting At-Risk Students', fontsize=14)
126
- plt.xlabel('Importance', fontsize=12)
127
- plt.ylabel('Feature', fontsize=12)
128
- plt.tight_layout()
129
- graphs.append(plt_to_base64())
130
-
131
- return graphs, tables
132
-
133
- def process_extra_curricular(df):
134
- df['extra_curricular_activities'] = df['extra_curricular_activities'].apply(
135
- lambda x: eval(x) if isinstance(x, str) else []
136
- )
137
- activities = df['extra_curricular_activities'].explode().unique()
138
- activities = [activity for activity in activities if activity is not None]
139
- for activity in activities:
140
- df[activity] = df['extra_curricular_activities'].apply(lambda x: int(activity in x))
141
- return df
142
-
143
- def analyze_extra_curricular_impact(df):
144
- graphs = []
145
- activity_cols = [col for col in df.columns if col in ['Cricket', 'Debating', 'Football', 'Art Club', 'Drama Club', 'Rugby']]
146
- for activity in activity_cols:
147
- if activity in df.columns:
148
- data = df.copy()
149
- group = data.groupby(activity)['credit_achievement_rate'].mean().reset_index()
150
- group[activity] = group[activity].map({0: 'Not Involved', 1: 'Involved'})
151
- plt.figure(figsize=(6, 4))
152
- sns.barplot(data=group, x=activity, y='credit_achievement_rate', palette='Set2', edgecolor='w', errorbar=None)
153
- plt.title(f'Impact of {activity} on Credit Achievement Rate', fontsize=14)
154
- plt.xlabel('Participation Status', fontsize=12)
155
- plt.ylabel('Average Credit Achievement Rate', fontsize=12)
156
- plt.tight_layout()
157
- graphs.append(plt_to_base64())
158
- return graphs
159
 
160
- def analyze_teacher_performance(df):
161
- graphs = []
162
- teacher_year_levels = {
163
- 'year_11_english_teacher': 'Year 11',
164
- 'year_11_maths_teacher': 'Year 11',
165
- 'year_12_english_teacher': 'Year 12',
166
- 'year_12_maths_teacher': 'Year 12'
167
- }
168
- for col, year_level in teacher_year_levels.items():
169
- data = df[(df[col] != 'Unknown') & (df['year_level'] == year_level)]
170
- if not data.empty:
171
- group = data.groupby(col)['credit_achievement_rate'].mean().reset_index()
172
- plt.figure(figsize=(10, 6))
173
- sns.barplot(data=group, x=col, y='credit_achievement_rate', palette='Set3', edgecolor='w', errorbar=None)
174
- plt.title(f'Average Credit Achievement Rate by {col.replace("_", " ").title()} ({year_level})', fontsize=14)
175
- plt.xlabel('Teacher', fontsize=12)
176
- plt.ylabel('Average Credit Achievement Rate', fontsize=12)
177
- plt.xticks(rotation=45)
178
- plt.tight_layout()
179
- graphs.append(plt_to_base64())
180
- return graphs
181
-
182
- def analyze_language_impact(df):
183
- graphs = []
184
- data = df[df['primary_language'] != 'Unknown']
185
- if not data.empty:
186
- group = data.groupby('primary_language')['credit_achievement_rate'].mean().reset_index()
187
  plt.figure(figsize=(10, 6))
188
- sns.barplot(data=group, x='primary_language', y='credit_achievement_rate', palette='Pastel1', edgecolor='w', errorbar=None)
189
- plt.title('Average Credit Achievement Rate by Primary Language', fontsize=14)
190
- plt.xlabel('Primary Language', fontsize=12)
191
- plt.ylabel('Average Credit Achievement Rate', fontsize=12)
192
- plt.xticks(rotation=45)
193
- plt.tight_layout()
194
- graphs.append(plt_to_base64())
195
- return graphs
196
-
197
- def perform_clustering(df):
198
- graphs = []
199
- tables = {}
200
- attendance_cols = [col for col in df.columns if 'attendance' in col]
201
- features = df[['credit_achievement_rate', 'age'] + attendance_cols]
202
- features = features.fillna(0)
203
- scaler = StandardScaler()
204
- scaled_features = scaler.fit_transform(features)
205
- pca = PCA(n_components=2)
206
- principal_components = pca.fit_transform(scaled_features)
207
- kmeans = KMeans(n_clusters=3, random_state=42)
208
- clusters = kmeans.fit_predict(principal_components)
209
- df['Cluster'] = clusters
210
- cluster_analysis = df.groupby('Cluster')[['credit_achievement_rate', 'age'] + attendance_cols].mean()
211
- tables['cluster_analysis'] = cluster_analysis.to_string()
212
- plt.figure(figsize=(8, 6))
213
- sns.scatterplot(x=principal_components[:,0], y=principal_components[:,1], hue=clusters, palette='Set1', s=100, alpha=0.7)
214
- plt.title('Student Clusters', fontsize=14)
215
- plt.xlabel('Principal Component 1', fontsize=12)
216
- plt.ylabel('Principal Component 2', fontsize=12)
217
- plt.legend(title='Cluster')
218
- plt.tight_layout()
219
- graphs.append(plt_to_base64())
220
- return graphs, tables
221
-
222
- def plot_correlation_with_credit_achievement(df):
223
- graphs = []
224
- tables = {}
225
- numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
226
- corr_matrix = df[numeric_cols].corr()
227
-
228
- if 'credit_achievement_rate' not in corr_matrix.columns:
229
- return graphs, tables
230
-
231
- corr_matrix = corr_matrix.drop(['credit_threshold', 'Total Credits'], axis=1, errors='ignore')
232
- corr_matrix = corr_matrix.drop(['credit_threshold', 'Total Credits'], axis=0, errors='ignore')
233
-
234
- correlation_with_credit = corr_matrix[['credit_achievement_rate']].sort_values(by='credit_achievement_rate', ascending=False)
235
-
236
- plt.figure(figsize=(8, 10))
237
- sns.heatmap(correlation_with_credit, annot=True, cmap='coolwarm', fmt='.2f', annot_kws={"size": 10}, cbar=True)
238
- plt.title('Correlation with Credit Achievement Rate', fontsize=16)
239
- plt.xticks(rotation=45, ha='right', fontsize=10)
240
  plt.tight_layout()
241
- graphs.append(plt_to_base64())
242
-
243
- tables['correlation_with_credit'] = correlation_with_credit.to_string()
244
-
245
- corr_matrix_clean = corr_matrix.replace([np.inf, -np.inf], np.nan).fillna(0)
246
-
247
- plt.figure(figsize=(12, 12))
248
- sns.clustermap(corr_matrix_clean, annot=False, cmap='coolwarm', figsize=(12, 12), method='average')
249
- plt.title('Cluster Map of Feature Correlations (excluding credit_threshold, Total Credits)', fontsize=16)
250
- graphs.append(plt_to_base64())
251
-
252
- return graphs, tables
253
-
254
- def plot_top_features_vs_credit(df):
255
- graphs = []
256
- numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
257
- corr_matrix = df[numeric_cols].corr()
258
-
259
- corr_matrix = corr_matrix.drop(['credit_threshold', 'Total Credits'], axis=0, errors='ignore')
260
- corr_matrix = corr_matrix.drop(['credit_threshold', 'Total Credits'], axis=1, errors='ignore')
261
-
262
- top_corr_features = corr_matrix['credit_achievement_rate'].abs().sort_values(ascending=False).index[1:6]
263
-
264
- for feature in top_corr_features:
265
- if pd.api.types.is_numeric_dtype(df[feature]):
266
- df_sorted = df[[feature, 'credit_achievement_rate']].sort_values(by=feature)
267
-
268
- plt.figure(figsize=(10, 6))
269
- sns.lineplot(x=df_sorted[feature], y=df_sorted['credit_achievement_rate'], marker='o')
270
- plt.title(f'Line Graph: {feature} vs Credit Achievement Rate', fontsize=14)
271
- plt.xlabel(feature.replace('_', ' ').title(), fontsize=12)
272
- plt.ylabel('Credit Achievement Rate', fontsize=12)
273
- plt.tight_layout()
274
- graphs.append(plt_to_base64())
275
- elif pd.api.types.is_categorical_dtype(df[feature]) or pd.api.types.is_object_dtype(df[feature]):
276
- group = df.groupby(feature)['credit_achievement_rate'].mean().reset_index()
277
-
278
- plt.figure(figsize=(10, 6))
279
- sns.barplot(x=group[feature], y=group['credit_achievement_rate'], palette='Set2')
280
- plt.title(f'Bar Plot: {feature} vs Credit Achievement Rate', fontsize=14)
281
- plt.xlabel(feature.replace('_', ' ').title(), fontsize=12)
282
- plt.ylabel('Average Credit Achievement Rate', fontsize=12)
283
- plt.xticks(rotation=45)
284
- plt.tight_layout()
285
- graphs.append(plt_to_base64())
286
-
287
- return graphs
288
-
289
- def plt_to_file():
290
- filename = f"temp_{uuid.uuid4()}.png"
291
- plt.savefig(filename)
292
  plt.close()
293
- return filename
294
-
295
- def perform_comprehensive_analysis(df):
296
- all_graphs = []
297
- all_tables = {}
298
-
299
- # 1. Identifying At-Risk Students
300
- graphs, tables = identify_at_risk_students(df)
301
- all_graphs.extend(graphs)
302
- all_tables.update(tables)
303
-
304
- # 2. Analyzing Impact of Extra-Curricular Activities
305
- df = process_extra_curricular(df)
306
- graphs = analyze_extra_curricular_impact(df)
307
- all_graphs.extend(graphs)
308
-
309
- # 3. Analyzing Teacher Performance
310
- graphs = analyze_teacher_performance(df)
311
- all_graphs.extend(graphs)
312
-
313
- # 4. Analyzing Language Proficiency Impact
314
- graphs = analyze_language_impact(df)
315
- all_graphs.extend(graphs)
316
-
317
- # 5. Performing Cluster Analysis
318
- graphs, tables = perform_clustering(df)
319
- all_graphs.extend(graphs)
320
- all_tables.update(tables)
321
-
322
- # 6. Correlation Analysis for Credit Achievement Rate
323
- graphs, tables = plot_correlation_with_credit_achievement(df)
324
- all_graphs.extend(graphs)
325
- all_tables.update(tables)
326
-
327
- # 7. Plotting Top Features vs Credit Achievement Rate
328
- graphs = plot_top_features_vs_credit(df)
329
- all_graphs.extend(graphs)
330
-
331
- return all_graphs, all_tables
332
 
333
- def gradio_wrapper(file):
334
- df = pd.read_csv(file.name)
335
- df = clean_data(df)
336
- graphs, tables = perform_comprehensive_analysis(df)
 
337
 
338
- # Convert tables to a list of strings for easier display
339
- table_outputs = [f"### {k}\n```\n{v}\n```" for k, v in tables.items()]
 
340
 
341
- return graphs + table_outputs
342
-
343
- # Create Gradio interface
344
- iface = gr.Interface(
345
- fn=gradio_wrapper,
346
- inputs=gr.File(label="Upload CSV"),
347
- outputs=[
348
- gr.Gallery(label="Graphs", columns=2, rows=3, height="auto"),
349
- gr.Markdown(label="Classification Report"),
350
- gr.Markdown(label="Feature Importance"),
351
- gr.Markdown(label="Cluster Analysis"),
352
- gr.Markdown(label="Correlation with Credit Achievement Rate")
353
- ],
354
- title="Comprehensive Student Data Analysis",
355
- description="Upload a CSV file to analyze student data. The analysis includes identifying at-risk students, impact of extra-curricular activities, teacher performance, language proficiency impact, cluster analysis, and correlation analysis."
356
- )
357
-
358
- # Launch the interface
359
- iface.launch()
360
-
361
- # Clean up temporary files
362
- def cleanup_temp_files():
363
- for filename in os.listdir():
364
- if filename.startswith("temp_") and filename.endswith(".png"):
365
- os.remove(filename)
366
 
367
- # Register the cleanup function to be called when the script exits
368
- import atexit
369
- atexit.register(cleanup_temp_files)
 
3
  import matplotlib.pyplot as plt
4
  import seaborn as sns
5
  import warnings
6
+ import gradio as gr
 
7
  from sklearn.model_selection import train_test_split
8
  from sklearn.ensemble import RandomForestClassifier
9
  from sklearn.metrics import classification_report
10
  from sklearn.preprocessing import StandardScaler
11
  from sklearn.cluster import KMeans
12
  from sklearn.decomposition import PCA
13
+ import io
14
 
15
  # Suppress specific FutureWarnings
16
  warnings.filterwarnings("ignore", category=FutureWarning)
 
38
 
39
  df = df.drop(columns=['nsn'], errors='ignore')
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  if 'ncea_results' in df.columns:
42
  ncea_results = []
43
  for idx, row in df.iterrows():
 
54
  else:
55
  df['Total Credits'] = 0
56
 
 
 
 
 
 
57
  df['credit_threshold'] = df['year_level'].apply(lambda x: 80 if x == 'Year 11' else 60)
58
  df['credit_achievement_rate'] = df['Total Credits'] / df['credit_threshold']
59
 
 
87
  model.fit(X_train, y_train)
88
  y_pred = model.predict(X_test)
89
 
90
+ classification_rep = classification_report(y_test, y_pred)
91
 
92
  importances = model.feature_importances_
93
  feature_names = features.columns
94
  feature_importance_df = pd.DataFrame({'Feature': feature_names, 'Importance': importances})
95
  feature_importance_df = feature_importance_df.sort_values(by='Importance', ascending=False)
96
 
97
+ return classification_rep, feature_importance_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
+ def plot_credit_achievement_rate(df):
100
+ """
101
+ Example analysis and plot function
102
+ """
103
+ if 'credit_achievement_rate' in df.columns:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  plt.figure(figsize=(10, 6))
105
+ sns.histplot(df['credit_achievement_rate'], kde=True, bins=30)
106
+ plt.title('Distribution of Credit Achievement Rate')
107
+ plt.xlabel('Credit Achievement Rate')
108
+ plt.ylabel('Frequency')
109
+ buf = io.BytesIO()
110
+ plt.savefig(buf, format='png')
111
+ buf.seek(0)
112
+ plt.close()
113
+ return buf
114
+ else:
115
+ return None
116
+
117
+ def plot_feature_importance(feature_importance_df):
118
+ """
119
+ Plot the top 10 important features for predicting at-risk students
120
+ """
121
+ plt.figure(figsize=(12, 6))
122
+ sns.barplot(data=feature_importance_df.head(10), x='Importance', y='Feature', palette='viridis')
123
+ plt.title('Top 10 Important Features for Predicting At-Risk Students', fontsize=14)
124
+ plt.xlabel('Importance', fontsize=12)
125
+ plt.ylabel('Feature', fontsize=12)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  plt.tight_layout()
127
+ buf = io.BytesIO()
128
+ plt.savefig(buf, format='png')
129
+ buf.seek(0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  plt.close()
131
+ return buf
132
+
133
+ def analyze_data(file):
134
+ try:
135
+ df = pd.read_csv(file)
136
+ df = clean_data(df)
137
+ # Generate classification report and feature importance
138
+ classification_rep, feature_importance_df = identify_at_risk_students(df)
139
+ # Generate plots
140
+ plot_buf = plot_credit_achievement_rate(df)
141
+ feature_importance_buf = plot_feature_importance(feature_importance_df)
142
+ result_text = f"Data analysis complete.\n\nClassification Report:\n{classification_rep}"
143
+ return result_text, plot_buf, feature_importance_buf
144
+ except Exception as e:
145
+ return f"An error occurred: {str(e)}", None, None
146
+
147
+ # Gradio Interface
148
+ def analyze_uploaded_file(file):
149
+ text, plot, feature_importance_plot = analyze_data(file)
150
+ if plot and feature_importance_plot:
151
+ return text, plot, feature_importance_plot
152
+ elif plot:
153
+ return text, plot, None
154
+ else:
155
+ return text, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
+ with gr.Blocks() as demo:
158
+ gr.Markdown("""
159
+ # Student Data Analysis Tool
160
+ Upload your CSV file to analyze student data and generate insights.
161
+ """)
162
 
163
+ with gr.Row():
164
+ file_input = gr.File(label="Upload CSV File")
165
+ text_output = gr.Textbox(label="Analysis Summary")
166
 
167
+ with gr.Row():
168
+ image_output = gr.Image(label="Generated Plot", type="pil")
169
+ feature_importance_output = gr.Image(label="Feature Importance Plot", type="pil")
170
+
171
+ file_input.change(analyze_uploaded_file, inputs=file_input, outputs=[text_output, image_output, feature_importance_output])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
+ demo.launch()