Update output rq2 table
Browse files
app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# app.py
|
| 2 |
import pandas as pd
|
| 3 |
import numpy as np
|
| 4 |
import matplotlib.pyplot as plt
|
|
@@ -8,20 +8,17 @@ from sklearn.preprocessing import StandardScaler
|
|
| 8 |
from sklearn.ensemble import RandomForestClassifier
|
| 9 |
from sklearn.model_selection import train_test_split
|
| 10 |
from sklearn.metrics import classification_report, roc_auc_score
|
| 11 |
-
from tabulate import tabulate
|
| 12 |
import warnings
|
| 13 |
-
import traceback
|
| 14 |
import gradio as gr
|
| 15 |
import os
|
| 16 |
import git
|
| 17 |
|
| 18 |
-
# --- Main Class
|
| 19 |
warnings.filterwarnings('ignore')
|
| 20 |
plt.style.use('default')
|
| 21 |
sns.set_palette("husl")
|
| 22 |
|
| 23 |
class EnhancedAIvsRealGazeAnalyzer:
|
| 24 |
-
# ... (The entire class from before remains unchanged up to run_prediction_model) ...
|
| 25 |
def __init__(self):
|
| 26 |
self.questions = ['Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6']
|
| 27 |
self.correct_answers = {'Pair1': 'B', 'Pair2': 'B', 'Pair3': 'B', 'Pair4': 'B', 'Pair5': 'B', 'Pair6': 'B'}
|
|
@@ -77,7 +74,6 @@ class EnhancedAIvsRealGazeAnalyzer:
|
|
| 77 |
return fig, summary
|
| 78 |
|
| 79 |
def run_prediction_model(self, test_size, n_estimators):
|
| 80 |
-
"""Runs the RandomForest model with given parameters for RQ2."""
|
| 81 |
leaky_features = ['Total_Correct', 'Overall_Accuracy', 'Correct']
|
| 82 |
features_to_use = [col for col in self.numeric_cols if col not in leaky_features]
|
| 83 |
features = self.combined_data[features_to_use].copy()
|
|
@@ -96,9 +92,11 @@ class EnhancedAIvsRealGazeAnalyzer:
|
|
| 96 |
report = classification_report(y_test, y_pred, target_names=['Incorrect', 'Correct'], output_dict=True)
|
| 97 |
auc_score = roc_auc_score(y_test, y_pred_proba)
|
| 98 |
|
| 99 |
-
# ---
|
|
|
|
| 100 |
report_df = pd.DataFrame(report).transpose().round(3)
|
| 101 |
-
|
|
|
|
| 102 |
|
| 103 |
report_md = f"""
|
| 104 |
### Model Performance
|
|
@@ -108,6 +106,7 @@ class EnhancedAIvsRealGazeAnalyzer:
|
|
| 108 |
**Classification Report:**
|
| 109 |
{report_table}
|
| 110 |
"""
|
|
|
|
| 111 |
|
| 112 |
feature_importance = pd.DataFrame({'Feature': features.columns, 'Importance': model.feature_importances_})
|
| 113 |
feature_importance = feature_importance.sort_values('Importance', ascending=False).head(15)
|
|
@@ -117,7 +116,7 @@ class EnhancedAIvsRealGazeAnalyzer:
|
|
| 117 |
plt.tight_layout()
|
| 118 |
return report_md, fig
|
| 119 |
|
| 120 |
-
# --- DATA SETUP
|
| 121 |
def setup_and_load_data():
|
| 122 |
repo_url = "https://github.com/RextonRZ/GenAIEyeTrackingCleanedDataset"
|
| 123 |
repo_dir = "GenAIEyeTrackingCleanedDataset"
|
|
@@ -152,47 +151,31 @@ description = """
|
|
| 152 |
Explore the eye-tracking dataset by interacting with the controls below. The data is automatically loaded from the public GitHub repository.
|
| 153 |
"""
|
| 154 |
|
| 155 |
-
# --- CHANGE 2: Restructure the layout with columns ---
|
| 156 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
| 157 |
gr.Markdown(description)
|
| 158 |
-
|
| 159 |
with gr.Tabs():
|
| 160 |
with gr.TabItem("RQ1: Viewing Time vs. Correctness"):
|
| 161 |
-
gr.Markdown("### Does viewing time differ based on whether a participant's answer was correct?")
|
| 162 |
with gr.Row():
|
| 163 |
with gr.Column(scale=1):
|
| 164 |
-
rq1_metric_dropdown = gr.Dropdown(
|
| 165 |
-
choices=analyzer.time_metrics,
|
| 166 |
-
label="Select a Time-Based Metric to Analyze",
|
| 167 |
-
value=analyzer.time_metrics[0] if analyzer.time_metrics else None
|
| 168 |
-
)
|
| 169 |
rq1_summary_output = gr.Markdown(label="Statistical Summary")
|
| 170 |
with gr.Column(scale=2):
|
| 171 |
rq1_plot_output = gr.Plot(label="Metric Comparison")
|
| 172 |
-
|
| 173 |
with gr.TabItem("RQ2: Predicting Correctness from Gaze"):
|
| 174 |
-
gr.Markdown("### Can we build a model to predict answer correctness from gaze patterns?")
|
| 175 |
with gr.Row():
|
| 176 |
-
# --- LEFT COLUMN FOR CONTROLS ---
|
| 177 |
with gr.Column(scale=1):
|
| 178 |
gr.Markdown("#### Tune Model Hyperparameters")
|
| 179 |
-
rq2_test_size_slider = gr.Slider(
|
| 180 |
-
|
| 181 |
-
)
|
| 182 |
-
rq2_estimators_slider = gr.Slider(
|
| 183 |
-
minimum=10, maximum=200, step=10, value=100, label="Number of Trees (n_estimators)"
|
| 184 |
-
)
|
| 185 |
-
# --- RIGHT COLUMN FOR OUTPUTS ---
|
| 186 |
with gr.Column(scale=2):
|
| 187 |
-
|
|
|
|
| 188 |
rq2_plot_output = gr.Plot(label="Feature Importance")
|
| 189 |
|
| 190 |
-
# Wire up the interactive components
|
| 191 |
rq1_metric_dropdown.change(fn=update_rq1_visuals, inputs=[rq1_metric_dropdown], outputs=[rq1_plot_output, rq1_summary_output])
|
| 192 |
rq2_test_size_slider.release(fn=update_rq2_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=[rq2_report_output, rq2_plot_output])
|
| 193 |
rq2_estimators_slider.release(fn=update_rq2_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=[rq2_report_output, rq2_plot_output])
|
| 194 |
|
| 195 |
-
# Load initial state
|
| 196 |
demo.load(fn=update_rq1_visuals, inputs=[rq1_metric_dropdown], outputs=[rq1_plot_output, rq1_summary_output])
|
| 197 |
demo.load(fn=update_rq2_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=[rq2_report_output, rq2_plot_output])
|
| 198 |
|
|
|
|
| 1 |
+
# app.py
|
| 2 |
import pandas as pd
|
| 3 |
import numpy as np
|
| 4 |
import matplotlib.pyplot as plt
|
|
|
|
| 8 |
from sklearn.ensemble import RandomForestClassifier
|
| 9 |
from sklearn.model_selection import train_test_split
|
| 10 |
from sklearn.metrics import classification_report, roc_auc_score
|
|
|
|
| 11 |
import warnings
|
|
|
|
| 12 |
import gradio as gr
|
| 13 |
import os
|
| 14 |
import git
|
| 15 |
|
| 16 |
+
# --- Main Class ---
|
| 17 |
warnings.filterwarnings('ignore')
|
| 18 |
plt.style.use('default')
|
| 19 |
sns.set_palette("husl")
|
| 20 |
|
| 21 |
class EnhancedAIvsRealGazeAnalyzer:
|
|
|
|
| 22 |
def __init__(self):
|
| 23 |
self.questions = ['Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6']
|
| 24 |
self.correct_answers = {'Pair1': 'B', 'Pair2': 'B', 'Pair3': 'B', 'Pair4': 'B', 'Pair5': 'B', 'Pair6': 'B'}
|
|
|
|
| 74 |
return fig, summary
|
| 75 |
|
| 76 |
def run_prediction_model(self, test_size, n_estimators):
|
|
|
|
| 77 |
leaky_features = ['Total_Correct', 'Overall_Accuracy', 'Correct']
|
| 78 |
features_to_use = [col for col in self.numeric_cols if col not in leaky_features]
|
| 79 |
features = self.combined_data[features_to_use].copy()
|
|
|
|
| 92 |
report = classification_report(y_test, y_pred, target_names=['Incorrect', 'Correct'], output_dict=True)
|
| 93 |
auc_score = roc_auc_score(y_test, y_pred_proba)
|
| 94 |
|
| 95 |
+
# --- THIS IS THE KEY FIX ---
|
| 96 |
+
# 1. Convert the report dictionary to a DataFrame
|
| 97 |
report_df = pd.DataFrame(report).transpose().round(3)
|
| 98 |
+
# 2. Use the built-in .to_markdown() method for perfect formatting
|
| 99 |
+
report_table = report_df.to_markdown()
|
| 100 |
|
| 101 |
report_md = f"""
|
| 102 |
### Model Performance
|
|
|
|
| 106 |
**Classification Report:**
|
| 107 |
{report_table}
|
| 108 |
"""
|
| 109 |
+
# --- END OF FIX ---
|
| 110 |
|
| 111 |
feature_importance = pd.DataFrame({'Feature': features.columns, 'Importance': model.feature_importances_})
|
| 112 |
feature_importance = feature_importance.sort_values('Importance', ascending=False).head(15)
|
|
|
|
| 116 |
plt.tight_layout()
|
| 117 |
return report_md, fig
|
| 118 |
|
| 119 |
+
# --- DATA SETUP ---
|
| 120 |
def setup_and_load_data():
|
| 121 |
repo_url = "https://github.com/RextonRZ/GenAIEyeTrackingCleanedDataset"
|
| 122 |
repo_dir = "GenAIEyeTrackingCleanedDataset"
|
|
|
|
| 151 |
Explore the eye-tracking dataset by interacting with the controls below. The data is automatically loaded from the public GitHub repository.
|
| 152 |
"""
|
| 153 |
|
|
|
|
| 154 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
| 155 |
gr.Markdown(description)
|
|
|
|
| 156 |
with gr.Tabs():
|
| 157 |
with gr.TabItem("RQ1: Viewing Time vs. Correctness"):
|
|
|
|
| 158 |
with gr.Row():
|
| 159 |
with gr.Column(scale=1):
|
| 160 |
+
rq1_metric_dropdown = gr.Dropdown(choices=analyzer.time_metrics, label="Select a Time-Based Metric", value=analyzer.time_metrics[0] if analyzer.time_metrics else None)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
rq1_summary_output = gr.Markdown(label="Statistical Summary")
|
| 162 |
with gr.Column(scale=2):
|
| 163 |
rq1_plot_output = gr.Plot(label="Metric Comparison")
|
|
|
|
| 164 |
with gr.TabItem("RQ2: Predicting Correctness from Gaze"):
|
|
|
|
| 165 |
with gr.Row():
|
|
|
|
| 166 |
with gr.Column(scale=1):
|
| 167 |
gr.Markdown("#### Tune Model Hyperparameters")
|
| 168 |
+
rq2_test_size_slider = gr.Slider(minimum=0.1, maximum=0.5, step=0.05, value=0.3, label="Test Set Size")
|
| 169 |
+
rq2_estimators_slider = gr.Slider(minimum=10, maximum=200, step=10, value=100, label="Number of Trees (n_estimators)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
with gr.Column(scale=2):
|
| 171 |
+
# Ensure this is gr.Markdown()
|
| 172 |
+
rq2_report_output = gr.Markdown(label="Model Performance Report")
|
| 173 |
rq2_plot_output = gr.Plot(label="Feature Importance")
|
| 174 |
|
|
|
|
| 175 |
rq1_metric_dropdown.change(fn=update_rq1_visuals, inputs=[rq1_metric_dropdown], outputs=[rq1_plot_output, rq1_summary_output])
|
| 176 |
rq2_test_size_slider.release(fn=update_rq2_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=[rq2_report_output, rq2_plot_output])
|
| 177 |
rq2_estimators_slider.release(fn=update_rq2_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=[rq2_report_output, rq2_plot_output])
|
| 178 |
|
|
|
|
| 179 |
demo.load(fn=update_rq1_visuals, inputs=[rq1_metric_dropdown], outputs=[rq1_plot_output, rq1_summary_output])
|
| 180 |
demo.load(fn=update_rq2_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=[rq2_report_output, rq2_plot_output])
|
| 181 |
|