diff --git "a/app.py" "b/app.py"
--- "a/app.py"
+++ "b/app.py"
@@ -9,1237 +9,1152 @@ import warnings
warnings.filterwarnings('ignore')
def install_package(package):
- """Install a package using pip"""
try:
- print(f"๐ฆ Installing {package}...")
subprocess.check_call([sys.executable, "-m", "pip", "install", package, "--quiet", "--no-warn-script-location"])
- print(f"โ
Successfully installed {package}")
return True
except Exception as e:
- print(f"โ Failed to install {package}: {e}")
+ print(f"Failed to install {package}: {e}")
return False
def install_all_packages():
- """Install all required packages"""
packages = [
- "numpy>=1.21.0",
- "pandas>=1.3.0",
- "matplotlib>=3.4.0",
- "seaborn>=0.11.0",
- "plotly>=5.0.0",
- "scikit-learn>=1.0.0",
- "tensorflow>=2.8.0",
- "keras>=2.8.0",
- "xgboost>=1.5.0",
- "lightgbm>=3.3.0",
- "catboost>=1.0.0",
- "requests>=2.25.0",
- "openpyxl>=3.0.0",
- "gradio>=4.0.0"
+ "numpy>=1.21.0", "pandas>=1.3.0", "matplotlib>=3.4.0",
+ "seaborn>=0.11.0", "plotly>=5.0.0", "scikit-learn>=1.0.0",
+ "xgboost>=1.5.0", "lightgbm>=3.3.0", "catboost>=1.0.0",
+ "requests>=2.25.0", "openpyxl>=3.0.0", "gradio>=4.0.0",
+ "scipy>=1.7.0"
]
-
- print("๐ Starting installation of all required packages...")
- print(f"๐ Total packages to install: {len(packages)}")
-
- success_count = 0
- for i, package in enumerate(packages, 1):
- print(f"\n[{i}/{len(packages)}] Processing {package}")
- if install_package(package):
- success_count += 1
-
- print(f"\n๐ Installation completed! {success_count}/{len(packages)} packages installed successfully.")
- return success_count == len(packages)
-
-# Install all packages at startup
-install_all_packages()
+ for package in packages:
+ install_package(package)
-# Import all packages
-print("\n๐ฅ Importing all packages...")
+install_all_packages()
+import gradio as gr
+import pandas as pd
+import numpy as np
+import matplotlib
+matplotlib.use('Agg')
+import matplotlib.pyplot as plt
+import seaborn as sns
+from sklearn.model_selection import train_test_split, cross_val_score, RandomizedSearchCV
+from sklearn.preprocessing import StandardScaler, LabelEncoder
+from sklearn.ensemble import (RandomForestClassifier, RandomForestRegressor,
+ GradientBoostingClassifier, GradientBoostingRegressor,
+ AdaBoostClassifier, AdaBoostRegressor,
+ ExtraTreesClassifier, ExtraTreesRegressor)
+from sklearn.linear_model import (LogisticRegression, LinearRegression,
+ Ridge, Lasso, ElasticNet)
+from sklearn.svm import SVC, SVR
+from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor
+from sklearn.naive_bayes import GaussianNB
+from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor
+from sklearn.cluster import KMeans
+from sklearn.metrics import (accuracy_score, f1_score, precision_score,
+ recall_score, mean_squared_error,
+ mean_absolute_error, r2_score,
+ classification_report, confusion_matrix,
+ roc_auc_score, silhouette_score)
+from scipy import stats
+
+# Optional imports
try:
- import gradio as gr
- import pandas as pd
- import numpy as np
- print("โ
Core packages imported")
-except ImportError as e:
- print(f"โ Core packages import failed: {e}")
+ import xgboost as xgb
+ XGBOOST_AVAILABLE = True
+except:
+ XGBOOST_AVAILABLE = False
try:
- import matplotlib
- matplotlib.use('Agg')
- import matplotlib.pyplot as plt
- import seaborn as sns
- import plotly.graph_objects as go
- import plotly.express as px
- from plotly.subplots import make_subplots
- print("โ
Visualization packages imported")
-except ImportError as e:
- print(f"โ Visualization packages import failed: {e}")
+ import lightgbm as lgb
+ LIGHTGBM_AVAILABLE = True
+except:
+ LIGHTGBM_AVAILABLE = False
try:
- from sklearn.model_selection import train_test_split, cross_val_score
- from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
- from sklearn.linear_model import LogisticRegression, LinearRegression
- from sklearn.svm import SVC, SVR
- from sklearn.metrics import accuracy_score, classification_report, mean_squared_error, r2_score
- from sklearn.preprocessing import StandardScaler, LabelEncoder
- from sklearn.cluster import KMeans
- print("โ
Scikit-learn imported")
-except ImportError as e:
- print(f"โ Scikit-learn import failed: {e}")
+ import catboost as cb
+ CATBOOST_AVAILABLE = True
+except:
+ CATBOOST_AVAILABLE = False
-try:
- import tensorflow as tf
- from tensorflow import keras
- from tensorflow.keras.models import Sequential
- from tensorflow.keras.layers import Dense, LSTM, Conv2D
- print("โ
TensorFlow and Keras imported")
-except ImportError as e:
- print(f"โ ๏ธ TensorFlow/Keras import failed (optional): {e}")
-try:
- import xgboost as xgb
- print("โ
XGBoost imported")
-except ImportError as e:
- print(f"โ ๏ธ XGBoost import failed (optional): {e}")
+# ============================================================
+# REAL DATA LOADER AGENT
+# ============================================================
+class DataLoaderAgent:
+ def load_data(self, source, source_type='csv', **kwargs):
+ try:
+ if source_type == 'csv':
+ data = pd.read_csv(source)
+ elif source_type == 'json':
+ data = pd.read_json(source)
+ elif source_type == 'excel':
+ data = pd.read_excel(source)
+ else:
+ raise ValueError(f"Unsupported source type: {source_type}")
-try:
- import lightgbm as lgb
- print("โ
LightGBM imported")
-except ImportError as e:
- print(f"โ ๏ธ LightGBM import failed (optional): {e}")
+ # Auto-detect datetime columns
+ for col in data.columns:
+ if data[col].dtype == 'object':
+ try:
+ data[col] = pd.to_datetime(data[col])
+ except:
+ pass
-try:
- import catboost as cb
- from catboost import CatBoostClassifier, CatBoostRegressor
- print("โ
CatBoost imported")
-except ImportError as e:
- print(f"โ ๏ธ CatBoost import failed (optional): {e}")
+ return {
+ 'status': 'success',
+ 'data': data,
+ 'info': {
+ 'shape': data.shape,
+ 'columns': list(data.columns),
+ 'dtypes': data.dtypes.astype(str).to_dict(),
+ 'memory_usage': f"{data.memory_usage(deep=True).sum() / 1024**2:.2f} MB"
+ }
+ }
+ except Exception as e:
+ return {'status': 'error', 'error': str(e), 'data': None}
+
+
+# ============================================================
+# REAL DATA CLEANING AGENT
+# ============================================================
+class DataCleaningAgent:
+ def clean_data(self, data, aggressive_cleaning=False):
+ cleaned = data.copy()
+ report = {'original_shape': data.shape, 'cleaning_steps': []}
+
+ # Handle missing values smartly
+ missing_info = {}
+ for col in cleaned.columns:
+ missing_count = cleaned[col].isnull().sum()
+ if missing_count > 0:
+ missing_info[col] = missing_count
+ if cleaned[col].dtype == 'object':
+ mode_val = cleaned[col].mode()
+ fill_val = mode_val[0] if len(mode_val) > 0 else 'Unknown'
+ cleaned[col].fillna(fill_val, inplace=True)
+ elif 'datetime' in str(cleaned[col].dtype):
+ cleaned[col].fillna(method='ffill', inplace=True)
+ else:
+ skewness = abs(cleaned[col].skew())
+ if skewness > 1:
+ cleaned[col].fillna(cleaned[col].median(), inplace=True)
+ else:
+ cleaned[col].fillna(cleaned[col].mean(), inplace=True)
+
+ report['missing_values'] = missing_info
+ report['cleaning_steps'].append('Missing values handled')
+
+ # Remove duplicates
+ initial_count = len(cleaned)
+ cleaned.drop_duplicates(inplace=True)
+ cleaned.reset_index(drop=True, inplace=True)
+ dups_removed = initial_count - len(cleaned)
+ report['duplicates_removed'] = dups_removed
+
+ # Handle outliers if aggressive
+ outlier_info = {}
+ if aggressive_cleaning:
+ for col in cleaned.select_dtypes(include=[np.number]).columns:
+ Q1 = cleaned[col].quantile(0.25)
+ Q3 = cleaned[col].quantile(0.75)
+ IQR = Q3 - Q1
+ if IQR == 0:
+ continue
+ lower = Q1 - 1.5 * IQR
+ upper = Q3 + 1.5 * IQR
+ outlier_count = ((cleaned[col] < lower) | (cleaned[col] > upper)).sum()
+ if outlier_count > 0:
+ outlier_info[col] = outlier_count
+ cleaned[col] = cleaned[col].clip(lower, upper)
+
+ report['outliers_handled'] = outlier_info
+
+ # Handle infinite values
+ for col in cleaned.select_dtypes(include=[np.number]).columns:
+ if np.isinf(cleaned[col]).any():
+ cleaned[col].replace([np.inf, -np.inf], np.nan, inplace=True)
+ cleaned[col].fillna(cleaned[col].median(), inplace=True)
+
+ report['final_shape'] = cleaned.shape
+ report['rows_removed'] = data.shape[0] - cleaned.shape[0]
+
+ return {'status': 'success', 'data': cleaned, 'cleaning_report': report}
+
+
+# ============================================================
+# REAL EDA AGENT
+# ============================================================
+class EDAAgent:
+ def analyze_data(self, data, target_column=None):
+ try:
+ analysis = {}
-try:
- import requests
- import openpyxl
- print("โ
Utility packages imported")
-except ImportError as e:
- print(f"โ Utility packages import failed: {e}")
-
-print("๐ All package imports completed!")
-
-class SafeDataAnalyzer:
- """Safe data analyzer that handles datetime and other special data types"""
-
- @staticmethod
- def detect_column_types(df):
- """Detect and categorize column types safely"""
- column_types = {
- 'numeric': [],
- 'categorical': [],
- 'datetime': [],
- 'boolean': [],
- 'text': []
- }
-
- for col in df.columns:
- dtype = str(df[col].dtype).lower()
-
- if 'datetime' in dtype or 'timestamp' in dtype:
- column_types['datetime'].append(col)
- elif 'bool' in dtype:
- column_types['boolean'].append(col)
- elif 'int' in dtype or 'float' in dtype:
- column_types['numeric'].append(col)
- elif 'object' in dtype:
- if df[col].nunique() < len(df) * 0.5 and df[col].nunique() < 50:
- column_types['categorical'].append(col)
+ # Column type detection
+ column_types = {
+ 'numeric': list(data.select_dtypes(include=[np.number]).columns),
+ 'categorical': list(data.select_dtypes(include=['object', 'category']).columns),
+ 'datetime': list(data.select_dtypes(include=['datetime64']).columns),
+ }
+ analysis['column_types'] = column_types
+
+ # Basic statistics
+ numeric_df = data[column_types['numeric']]
+ analysis['basic_stats'] = {}
+ if not numeric_df.empty:
+ analysis['basic_stats']['describe'] = numeric_df.describe().to_dict()
+ analysis['basic_stats']['skewness'] = numeric_df.skew().to_dict()
+ analysis['basic_stats']['kurtosis'] = numeric_df.kurtosis().to_dict()
+
+ # Correlation matrix
+ analysis['correlations'] = {}
+ if len(column_types['numeric']) > 1:
+ corr_matrix = data[column_types['numeric']].corr()
+ analysis['correlations']['matrix'] = corr_matrix.to_dict()
+
+ # Strong correlations
+ strong = []
+ for i in range(len(corr_matrix.columns)):
+ for j in range(i+1, len(corr_matrix.columns)):
+ val = corr_matrix.iloc[i, j]
+ if not np.isnan(val) and abs(val) > 0.7:
+ strong.append({
+ 'var1': corr_matrix.columns[i],
+ 'var2': corr_matrix.columns[j],
+ 'correlation': round(val, 3)
+ })
+ analysis['correlations']['strong'] = strong
+
+ # Missing values
+ analysis['missing_values'] = data.isnull().sum().to_dict()
+
+ # Duplicate count
+ analysis['duplicates'] = int(data.duplicated().sum())
+
+ # Data quality score
+ total_cells = data.shape[0] * data.shape[1]
+ missing_cells = data.isnull().sum().sum()
+ analysis['data_quality_score'] = round(
+ (1 - missing_cells / total_cells) * 100, 1
+ )
+
+ # Target analysis
+ if target_column and target_column in data.columns:
+ target = data[target_column]
+ is_classification = (
+ target.dtype == 'object' or target.nunique() < 20
+ )
+ analysis['target_analysis'] = {
+ 'type': 'classification' if is_classification else 'regression',
+ 'unique_values': int(target.nunique()),
+ 'missing': int(target.isnull().sum())
+ }
+ if is_classification:
+ analysis['target_analysis']['class_distribution'] = (
+ target.value_counts().to_dict()
+ )
else:
- column_types['text'].append(col)
+ analysis['target_analysis']['stats'] = {
+ 'mean': round(float(target.mean()), 4),
+ 'median': round(float(target.median()), 4),
+ 'std': round(float(target.std()), 4),
+ 'skewness': round(float(target.skew()), 4)
+ }
+
+ return {'status': 'success', 'analysis': analysis}
+
+ except Exception as e:
+ return {'status': 'error', 'error': str(e), 'analysis': {}}
+
+
+# ============================================================
+# REAL MODEL BUILDING AGENT
+# ============================================================
+class ModelBuildingAgent:
+ def __init__(self):
+ self.scaler = StandardScaler()
+ self.label_encoders = {}
+
+ def _preprocess(self, X):
+ X_proc = X.copy()
+
+ # Drop datetime columns
+ datetime_cols = X_proc.select_dtypes(include=['datetime64']).columns
+ X_proc.drop(columns=datetime_cols, inplace=True)
+
+ # Encode categoricals
+ for col in X_proc.select_dtypes(include=['object']).columns:
+ if X_proc[col].nunique() <= 10:
+ dummies = pd.get_dummies(X_proc[col], prefix=col, drop_first=True)
+ X_proc = pd.concat([X_proc, dummies], axis=1)
+ X_proc.drop(columns=[col], inplace=True)
else:
- column_types['categorical'].append(col)
-
- return column_types
-
- @staticmethod
- def safe_describe(df):
- """Safely describe dataframe without breaking on datetime columns"""
+ le = LabelEncoder()
+ X_proc[col] = le.fit_transform(X_proc[col].astype(str))
+ self.label_encoders[col] = le
+
+ # Fill missing
+ X_proc.fillna(X_proc.median(numeric_only=True), inplace=True)
+ X_proc.replace([np.inf, -np.inf], np.nan, inplace=True)
+ X_proc.fillna(0, inplace=True)
+
+ return X_proc
+
+ def _detect_problem_type(self, y):
+ if y.dtype == 'object' or y.nunique() < 20:
+ return 'classification'
+ return 'regression'
+
+ def build_models(self, data, target_column):
try:
- column_types = SafeDataAnalyzer.detect_column_types(df)
-
- description = {}
-
- if column_types['numeric']:
- numeric_df = df[column_types['numeric']]
- description['numeric'] = numeric_df.describe()
+ X = data.drop(columns=[target_column])
+ y = data[target_column]
+
+ problem_type = self._detect_problem_type(y)
+
+ X_proc = self._preprocess(X)
+
+ # Encode target if classification
+ if problem_type == 'classification' and y.dtype == 'object':
+ le = LabelEncoder()
+ y = le.fit_transform(y)
+ self.label_encoders['target'] = le
+
+ # Train-test split
+ X_train, X_test, y_train, y_test = train_test_split(
+ X_proc, y, test_size=0.2, random_state=42,
+ stratify=y if problem_type == 'classification' else None
+ )
+
+ # Scale
+ X_train_scaled = self.scaler.fit_transform(X_train)
+ X_test_scaled = self.scaler.transform(X_test)
+
+ # Define models
+ if problem_type == 'classification':
+ models = {
+ 'Logistic Regression': LogisticRegression(max_iter=1000, random_state=42),
+ 'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
+ 'Gradient Boosting': GradientBoostingClassifier(random_state=42),
+ 'Extra Trees': ExtraTreesClassifier(n_estimators=100, random_state=42),
+ 'SVM': SVC(probability=True, random_state=42),
+ 'KNN': KNeighborsClassifier(n_neighbors=5),
+ 'Naive Bayes': GaussianNB(),
+ 'Decision Tree': DecisionTreeClassifier(random_state=42),
+ 'AdaBoost': AdaBoostClassifier(random_state=42),
+ }
+ else:
+ models = {
+ 'Linear Regression': LinearRegression(),
+ 'Ridge': Ridge(random_state=42),
+ 'Lasso': Lasso(random_state=42),
+ 'Random Forest': RandomForestRegressor(n_estimators=100, random_state=42),
+ 'Gradient Boosting': GradientBoostingRegressor(random_state=42),
+ 'Extra Trees': ExtraTreesRegressor(n_estimators=100, random_state=42),
+ 'SVR': SVR(),
+ 'KNN': KNeighborsRegressor(n_neighbors=5),
+ 'Decision Tree': DecisionTreeRegressor(random_state=42),
+ 'AdaBoost': AdaBoostRegressor(random_state=42),
+ }
+
+ # Optional boosting models
+ if XGBOOST_AVAILABLE:
+ if problem_type == 'classification':
+ models['XGBoost'] = xgb.XGBClassifier(
+ random_state=42, eval_metric='logloss', verbosity=0
+ )
+ else:
+ models['XGBoost'] = xgb.XGBRegressor(random_state=42, verbosity=0)
+
+ if LIGHTGBM_AVAILABLE:
+ if problem_type == 'classification':
+ models['LightGBM'] = lgb.LGBMClassifier(random_state=42, verbose=-1)
+ else:
+ models['LightGBM'] = lgb.LGBMRegressor(random_state=42, verbose=-1)
+
+ if CATBOOST_AVAILABLE:
+ if problem_type == 'classification':
+ models['CatBoost'] = cb.CatBoostClassifier(random_state=42, verbose=False)
+ else:
+ models['CatBoost'] = cb.CatBoostRegressor(random_state=42, verbose=False)
+
+ # Train and evaluate all models
+ results = {}
+ for name, model in models.items():
try:
- description['skewness'] = numeric_df.skew()
- except Exception as e:
- print(f"Warning: Could not calculate skewness: {e}")
- description['skewness'] = pd.Series()
-
- if column_types['categorical']:
- categorical_df = df[column_types['categorical']]
- description['categorical'] = categorical_df.describe()
-
- if column_types['datetime']:
- datetime_df = df[column_types['datetime']]
- description['datetime'] = {}
- for col in column_types['datetime']:
- try:
- description['datetime'][col] = {
- 'min': datetime_df[col].min(),
- 'max': datetime_df[col].max(),
- 'unique_count': datetime_df[col].nunique()
+ model.fit(X_train_scaled, y_train)
+ y_pred = model.predict(X_test_scaled)
+
+ if problem_type == 'classification':
+ metrics = {
+ 'accuracy': round(accuracy_score(y_test, y_pred), 4),
+ 'f1_score': round(f1_score(y_test, y_pred, average='weighted', zero_division=0), 4),
+ 'precision': round(precision_score(y_test, y_pred, average='weighted', zero_division=0), 4),
+ 'recall': round(recall_score(y_test, y_pred, average='weighted', zero_division=0), 4),
}
- except Exception as e:
- print(f"Warning: Could not analyze datetime column {col}: {e}")
-
- return description, column_types
- except Exception as e:
- print(f"Error in safe_describe: {e}")
- return {}, {'numeric': [], 'categorical': [], 'datetime': [], 'boolean': [], 'text': []}
-
- @staticmethod
- def safe_correlation(df):
- """Safely calculate correlation matrix for numeric columns only"""
- try:
- column_types = SafeDataAnalyzer.detect_column_types(df)
- numeric_cols = column_types['numeric']
-
- if len(numeric_cols) > 1:
- return df[numeric_cols].corr()
+ # ROC AUC for binary
+ if len(np.unique(y_test)) == 2 and hasattr(model, 'predict_proba'):
+ try:
+ y_prob = model.predict_proba(X_test_scaled)[:, 1]
+ metrics['roc_auc'] = round(roc_auc_score(y_test, y_prob), 4)
+ except:
+ pass
+ else:
+ metrics = {
+ 'rmse': round(float(mean_squared_error(y_test, y_pred, squared=False)), 4),
+ 'mae': round(float(mean_absolute_error(y_test, y_pred)), 4),
+ 'r2_score': round(float(r2_score(y_test, y_pred)), 4),
+ }
+
+ results[name] = {**metrics, 'model': model, 'status': 'success'}
+
+ except Exception as e:
+ results[name] = {'status': 'error', 'error': str(e)}
+
+ # Select best model
+ valid = {k: v for k, v in results.items() if v['status'] == 'success'}
+ if not valid:
+ return {'status': 'error', 'error': 'No models trained successfully'}
+
+ if problem_type == 'classification':
+ best_name = max(valid.keys(), key=lambda x: valid[x]['accuracy'])
else:
- return pd.DataFrame()
+ best_name = min(valid.keys(), key=lambda x: valid[x]['rmse'])
+
+ # Feature importance
+ best_model = valid[best_name]['model']
+ feature_importance = {}
+ try:
+ if hasattr(best_model, 'feature_importances_'):
+ fi = dict(zip(X_proc.columns, best_model.feature_importances_))
+ feature_importance = dict(
+ sorted(fi.items(), key=lambda x: x[1], reverse=True)
+ )
+ elif hasattr(best_model, 'coef_'):
+ coef = best_model.coef_ if len(best_model.coef_.shape) == 1 else best_model.coef_[0]
+ fi = dict(zip(X_proc.columns, np.abs(coef)))
+ feature_importance = dict(
+ sorted(fi.items(), key=lambda x: x[1], reverse=True)
+ )
+ except:
+ pass
+
+ return {
+ 'status': 'success',
+ 'problem_type': problem_type,
+ 'results': results,
+ 'best_model': best_name,
+ 'feature_importance': feature_importance,
+ 'n_features': X_proc.shape[1],
+ 'train_size': len(X_train),
+ 'test_size': len(X_test),
+ }
+
except Exception as e:
- print(f"Warning: Could not calculate correlation: {e}")
- return pd.DataFrame()
+ return {'status': 'error', 'error': str(e)}
+
+
+# ============================================================
+# REAL DOMAIN EXPERT AGENT
+# ============================================================
+class DomainExpertAgent:
+ def __init__(self):
+ self.domain_keywords = {
+ 'finance': ['price', 'revenue', 'profit', 'cost', 'sales', 'income',
+ 'expense', 'balance', 'rate', 'return', 'amount'],
+ 'healthcare': ['age', 'bmi', 'weight', 'height', 'diagnosis', 'treatment',
+ 'patient', 'doctor', 'medication', 'symptoms', 'blood'],
+ 'retail': ['product', 'category', 'quantity', 'discount', 'store',
+ 'customer', 'purchase', 'inventory', 'brand', 'order'],
+ 'marketing': ['campaign', 'clicks', 'impressions', 'conversion',
+ 'engagement', 'audience', 'channel', 'ctr', 'budget'],
+ }
+
+ def detect_domain(self, data):
+ col_text = ' '.join(data.columns).lower()
+ scores = {}
+ for domain, keywords in self.domain_keywords.items():
+ score = sum(1 for kw in keywords if kw in col_text)
+ scores[domain] = score
+
+ if max(scores.values()) > 0:
+ return max(scores, key=scores.get)
+ return 'general'
+
+ def provide_insights(self, data, domain=None, target_column=None):
+ if not domain:
+ domain = self.detect_domain(data)
+
+ insights = [
+ f"Dataset contains {data.shape[0]:,} records with {data.shape[1]} features",
+ f"Detected domain: {domain.title()}",
+ ]
+
+ numeric_cols = data.select_dtypes(include=[np.number]).columns
+ categorical_cols = data.select_dtypes(include=['object']).columns
+
+ if len(numeric_cols) > 1:
+ insights.append(f"{len(numeric_cols)} numeric features available for analysis")
+ if len(categorical_cols) > 0:
+ insights.append(f"{len(categorical_cols)} categorical features detected")
+
+ missing = data.isnull().sum().sum()
+ if missing > 0:
+ insights.append(f"Found {missing:,} missing values โ handled during cleaning")
+
+ recommendations = [
+ "Use cross-validation for robust model evaluation",
+ "Monitor for data drift in production",
+ ]
+
+ if len(numeric_cols) > 10:
+ recommendations.append("Consider dimensionality reduction (PCA)")
+ if len(categorical_cols) > 0:
+ recommendations.append("Apply proper encoding for categorical features")
+
+ return {
+ 'detected_domain': domain,
+ 'insights': insights,
+ 'recommendations': recommendations,
+ }
-class SupervisorAgentMock:
- """Enhanced mock supervisor with safe data handling"""
-
+
+# ============================================================
+# REAL SUPERVISOR AGENT (No Mock!)
+# ============================================================
+class SupervisorAgent:
def __init__(self):
- self.analyzer = SafeDataAnalyzer()
-
- def execute_pipeline(self, data_source, source_type='csv', target_column=None, domain=None, **kwargs):
+ self.data_loader = DataLoaderAgent()
+ self.data_cleaner = DataCleaningAgent()
+ self.eda_agent = EDAAgent()
+ self.domain_expert = DomainExpertAgent()
+ self.model_builder = ModelBuildingAgent()
+
+ def execute_pipeline(self, data_source, source_type='csv',
+ target_column=None, domain=None, **kwargs):
try:
- if source_type == 'csv':
- df = pd.read_csv(data_source)
- elif source_type == 'json':
- df = pd.read_json(data_source)
- else:
- raise ValueError(f"Unsupported file type: {source_type}")
-
- for col in df.columns:
- if df[col].dtype == 'object':
- try:
- pd.to_datetime(df[col], infer_datetime_format=True)
- df[col] = pd.to_datetime(df[col])
- except:
- pass
-
- description, column_types = self.analyzer.safe_describe(df)
- correlation_matrix = self.analyzer.safe_correlation(df)
-
+ # Step 1: Load data
+ load_result = self.data_loader.load_data(data_source, source_type)
+ if load_result['status'] != 'success':
+ return {'status': 'error', 'error': load_result['error']}
+
+ data = load_result['data']
+
+ # Step 2: Clean data
+ clean_result = self.data_cleaner.clean_data(data)
+ if clean_result['status'] != 'success':
+ return {'status': 'error', 'error': clean_result['error']}
+
+ cleaned_data = clean_result['data']
+ cleaning_report = clean_result['cleaning_report']
+
+ # Step 3: EDA
+ eda_result = self.eda_agent.analyze_data(cleaned_data, target_column)
+
+ # Step 4: Domain insights
+ domain_result = self.domain_expert.provide_insights(
+ cleaned_data, domain, target_column
+ )
+
+ # Step 5: Model building (only if target specified)
+ model_result = {}
+ if target_column and target_column in cleaned_data.columns:
+ model_result = self.model_builder.build_models(cleaned_data, target_column)
+
return {
'status': 'success',
'pipeline_results': {
'data_loading': {
'status': 'success',
- 'info': {
- 'shape': df.shape,
- 'columns': list(df.columns),
- 'dtypes': df.dtypes.astype(str).to_dict(),
- 'column_types': column_types,
- 'memory_usage': f"{df.memory_usage(deep=True).sum() / 1024**2:.2f} MB"
- }
+ 'info': load_result['info']
},
'data_cleaning': {
'status': 'success',
- 'cleaning_report': {
- 'duplicates_removed': df.duplicated().sum(),
- 'missing_values': df.isnull().sum().to_dict(),
- 'outliers_handled': self._safe_outlier_detection(df, column_types['numeric'])
- }
+ 'cleaning_report': cleaning_report
},
- 'eda': {
- 'status': 'success',
- 'analysis': {
- 'basic_stats': description,
- 'column_types': column_types,
- 'correlations': {
- 'correlation_matrix': correlation_matrix.to_dict() if not correlation_matrix.empty else {}
- }
- }
- },
- 'domain_insights': {
- 'detected_domain': domain or 'general',
- 'insights': self._generate_domain_insights(df, domain, column_types),
- 'recommendations': self._generate_recommendations(df, column_types, target_column)
- },
- 'modeling': self._safe_modeling_results(df, target_column, column_types) if target_column else {}
+ 'eda': eda_result,
+ 'domain_insights': domain_result,
+ 'modeling': model_result,
},
- 'summary': {
- 'key_insights': self._generate_key_insights(df, column_types, target_column),
- 'recommendations': self._generate_final_recommendations(df, column_types, domain)
- }
+ 'data': cleaned_data,
}
+
except Exception as e:
- return {
- 'status': 'error',
- 'error': str(e),
- 'pipeline_results': {},
- 'summary': {'key_insights': [], 'recommendations': []}
- }
-
- def _safe_outlier_detection(self, df, numeric_cols):
- """Safely detect outliers in numeric columns"""
- outliers = {}
- for col in numeric_cols:
- try:
- Q1 = df[col].quantile(0.25)
- Q3 = df[col].quantile(0.75)
- IQR = Q3 - Q1
- lower_bound = Q1 - 1.5 * IQR
- upper_bound = Q3 + 1.5 * IQR
- outliers[col] = len(df[(df[col] < lower_bound) | (df[col] > upper_bound)])
- except Exception as e:
- outliers[col] = 0
- return outliers
-
- def _generate_domain_insights(self, df, domain, column_types):
- """Generate domain-specific insights"""
- insights = [
- f"Dataset contains {df.shape[0]:,} records with {df.shape[1]} features",
- f"Data types: {len(column_types['numeric'])} numeric, {len(column_types['categorical'])} categorical, {len(column_types['datetime'])} datetime"
- ]
-
- if domain:
- insights.append(f"Dataset optimized for {domain.title()} domain analysis")
-
- if column_types['datetime']:
- insights.append(f"Time series analysis possible with {len(column_types['datetime'])} datetime columns")
-
- return insights
-
- def _generate_recommendations(self, df, column_types, target_column):
- """Generate recommendations based on data analysis"""
- recommendations = []
-
- if len(column_types['numeric']) > 1:
- recommendations.append("Consider feature scaling for numeric variables")
-
- if column_types['datetime']:
- recommendations.append("Extract time-based features (day, month, seasonality)")
-
- if len(column_types['categorical']) > 0:
- recommendations.append("Apply appropriate encoding for categorical variables")
-
- if target_column and target_column in column_types['categorical']:
- recommendations.append("Classification problem detected - consider ensemble methods")
- elif target_column and target_column in column_types['numeric']:
- recommendations.append("Regression problem detected - evaluate feature importance")
-
- return recommendations
-
- def _safe_modeling_results(self, df, target_column, column_types):
- """Generate safe modeling results"""
- if not target_column or target_column not in df.columns:
- return {}
-
- is_classification = target_column in column_types['categorical'] or df[target_column].nunique() < 20
-
- return {
- 'status': 'success',
- 'problem_type': 'classification' if is_classification else 'regression',
- 'best_model': 'Random Forest',
- 'results': {
- 'Random Forest': {'accuracy': 0.87, 'f1_score': 0.85} if is_classification else {'rmse': 0.45, 'r2_score': 0.82},
- 'SVM': {'accuracy': 0.82, 'f1_score': 0.80} if is_classification else {'rmse': 0.52, 'r2_score': 0.78},
- 'LogisticRegression': {'accuracy': 0.78, 'f1_score': 0.76} if is_classification else {'rmse': 0.58, 'r2_score': 0.74}
- },
- 'feature_importance': {col: np.random.random() for col in df.columns if col != target_column and col in column_types['numeric']}
- }
-
- def _generate_key_insights(self, df, column_types, target_column):
- """Generate key insights from the analysis"""
- insights = [
- f"Dataset contains {df.shape[0]:,} samples with {df.shape[1]} features",
- f"Data quality is {(1 - df.isnull().sum().sum() / (df.shape[0] * df.shape[1])) * 100:.1f}% complete"
- ]
-
- if len(column_types['numeric']) > 1:
- insights.append("Multiple numeric features available for correlation analysis")
-
- if column_types['datetime']:
- insights.append("Time-based patterns can be analyzed for temporal insights")
-
- return insights
-
- def _generate_final_recommendations(self, df, column_types, domain):
- """Generate final recommendations"""
- recommendations = [
- "Consider cross-validation for robust model evaluation",
- "Monitor data drift in production environment"
- ]
-
- if len(column_types['numeric']) > 10:
- recommendations.append("Consider dimensionality reduction techniques")
-
- if domain in ['finance', 'healthcare']:
- recommendations.append("Implement additional validation for regulatory compliance")
-
- return recommendations
+ return {'status': 'error', 'error': str(e)}
-class DataSciencePipelineUI:
- """Advanced UI for the comprehensive data science pipeline with safe data handling"""
+# ============================================================
+# UI CLASS
+# ============================================================
+class DataSciencePipelineUI:
def __init__(self):
- self.supervisor = SupervisorAgentMock()
- self.analyzer = SafeDataAnalyzer()
+ self.supervisor = SupervisorAgent() # REAL agent now!
self.current_data = None
self.pipeline_results = None
- self.processing_step = 0
- self.total_steps = 6
- self.plot_images = {} # Store base64 images for report
-
- self.custom_css = """
- .main-container {
- max-width: 1400px;
- margin: 0 auto;
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- }
- .step-container {
- margin: 15px 0;
- padding: 20px;
- border-radius: 12px;
- border-left: 5px solid #3498db;
- background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
- }
- .step-header {
- display: flex;
- align-items: center;
- margin-bottom: 10px;
- }
- .step-icon {
- font-size: 24px;
- margin-right: 15px;
- }
- .progress-bar {
- background: linear-gradient(90deg, #4CAF50, #45a049);
- height: 6px;
- border-radius: 3px;
- margin: 10px 0;
- }
- """
+ self.plot_images = {}
def create_plot_html(self, fig, plot_id=None):
- """Convert matplotlib figure to HTML and store for report"""
buf = BytesIO()
fig.savefig(buf, format='png', dpi=100, bbox_inches='tight', facecolor='white')
buf.seek(0)
img_str = base64.b64encode(buf.getvalue()).decode('utf-8')
buf.close()
plt.close(fig)
-
if plot_id:
self.plot_images[plot_id] = img_str
-
- return f''
+ return f'
'
def process_file_upload(self, file_obj, learning_type):
- """Enhanced file processing with safe datetime handling"""
if file_obj is None:
return "โ No file uploaded", "", [], gr.update(visible=False), ""
try:
file_path = file_obj.name
- file_name = os.path.basename(file_path)
- file_extension = os.path.splitext(file_name)[1].lower()
+ ext = os.path.splitext(file_path)[1].lower()
- if file_extension == '.csv':
+ if ext == '.csv':
df = pd.read_csv(file_path)
- file_type = 'csv'
- elif file_extension == '.json':
+ elif ext == '.json':
df = pd.read_json(file_path)
- file_type = 'json'
+ elif ext in ['.xlsx', '.xls']:
+ df = pd.read_excel(file_path)
else:
- return "โ Unsupported file type. Please upload CSV or JSON files only.", "", [], gr.update(visible=False), ""
-
- for col in df.columns:
- if df[col].dtype == 'object':
- try:
- pd.to_datetime(df[col], infer_datetime_format=True, errors='raise')
- df[col] = pd.to_datetime(df[col])
- except:
- pass
+ return "โ Unsupported file type. Use CSV, JSON, or Excel.", "", [], gr.update(visible=False), ""
self.current_data = df
- description, column_types = self.analyzer.safe_describe(df)
-
- file_size = os.path.getsize(file_path) / 1024
- memory_usage = df.memory_usage(deep=True).sum() / 1024**2
- missing_count = df.isnull().sum().sum()
- duplicate_count = df.duplicated().sum()
-
- preview_html = self._create_safe_data_preview(df)
+ missing = df.isnull().sum().sum()
+ dups = df.duplicated().sum()
+ numeric_cols = df.select_dtypes(include=[np.number]).columns
+ cat_cols = df.select_dtypes(include=['object']).columns
file_info = f"""
-
Name: {file_name}
-Type: {file_type.upper()}
-Size: {file_size:.2f} KB
+Rows: {df.shape[0]:,}
-Columns: {df.shape[1]}
-Memory: {memory_usage:.2f} MB
+Missing: {missing_count:,} values
-Duplicates: {duplicate_count:,} rows
-Quality: {((1 - (missing_count + duplicate_count) / (df.shape[0] * df.shape[1])) * 100):.1f}%
-Numeric: {len(column_types['numeric'])}
-Categorical: {len(column_types['categorical'])}
-DateTime: {len(column_types['datetime'])}
+| {col} | " + table_html += "
|---|
| {cell} | " + table_html += "
| {col} | " - html += "
|---|
| {cell_value} | " - html += "
No target column โ skipped.
") - def _create_error_html(self, message): - return f""" -{message}
-End-to-end automated machine learning pipeline with comprehensive analysis
-Started: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
-+ Real multi-agent automated ML โ {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} +
Data loading information not available
" - - info = results.get('info', {}) + def _format_loading(self, result): + if not result: + return "No loading info.
" + info = result.get('info', {}) shape = info.get('shape', (0, 0)) - column_types = info.get('column_types', {}) - return f""" -Rows: {shape[0]:,}
-Columns: {shape[1]}
-Memory: {info.get('memory_usage', 'Unknown')}
+Numeric: {len(column_types.get('numeric', []))}
-Categorical: {len(column_types.get('categorical', []))}
-DateTime: {len(column_types.get('datetime', []))}
+โ Data loaded and column types detected successfully!
""" - def _format_data_cleaning_results(self, results): - """Format data cleaning results""" - if not results or results.get('status') != 'success': - return "Data cleaning information not available
" - - report = results.get('cleaning_report', {}) - duplicates = report.get('duplicates_removed', 0) - missing_values = report.get('missing_values', {}) + def _format_cleaning(self, result): + if not result: + return "No cleaning info.
" + report = result.get('cleaning_report', {}) + missing = report.get('missing_values', {}) + total_missing = sum(missing.values()) if isinstance(missing, dict) else 0 + dups = report.get('duplicates_removed', 0) outliers = report.get('outliers_handled', {}) - - total_missing = sum(missing_values.values()) if isinstance(missing_values, dict) else 0 total_outliers = sum(outliers.values()) if isinstance(outliers, dict) else 0 return f""" -Duplicates Removed: {duplicates}
-Missing Values: {total_missing}
-Outliers Handled: {total_outliers}
+โ Data cleaning completed successfully!
++ Final shape: {report.get('final_shape','N/A')} +
""" - def _create_dynamic_histogram(self, data, column): - """Create a dynamic histogram for a numeric column""" - try: - values = data[column].dropna() - if len(values) == 0: - return "No valid data for histogram
" - - # Dynamically adjust number of bins based on data size and spread - n_bins = min(max(int(np.sqrt(len(values))), 10), 50) - plt.figure(figsize=(8, 6)) - sns.histplot(values, bins=n_bins, kde=True, color='skyblue') - plt.title(f'Distribution of {column}', fontsize=14) - plt.xlabel(column, fontsize=12) - plt.ylabel('Count', fontsize=12) - - # Add range and stats annotations - stats_text = f'Min: {values.min():.2f}\nMax: {values.max():.2f}\nMean: {values.mean():.2f}' - plt.text(0.95, 0.95, stats_text, transform=plt.gca().transAxes, ha='right', va='top', - bbox=dict(facecolor='white', alpha=0.8)) - - html = self.create_plot_html(plt.gcf(), f"histogram_{column}") - plt.close() - - return f""" - {html} -Histogram showing the distribution of {column}
- """ - except Exception as e: - return f"Could not generate histogram for {column}: {str(e)}
" - - def _create_dynamic_bar(self, data, column, is_target=False): - """Create a dynamic bar plot for a categorical column""" - try: - value_counts = data[column].value_counts().head(10) # Limit to top 10 categories - labels = value_counts.index.tolist() - counts = value_counts.values.tolist() - - plt.figure(figsize=(8, 6)) - sns.barplot(x=counts, y=labels, palette='tab10') - plt.title(f"{'Target Distribution' if is_target else f'Distribution of {column}'}", fontsize=14) - plt.xlabel('Count', fontsize=12) - plt.ylabel(column, fontsize=12) - - # Add total count annotation - plt.text(0.95, 0.95, f'Total: {sum(counts)}', - transform=plt.gca().transAxes, ha='right', va='top', bbox=dict(facecolor='white', alpha=0.8)) - - html = self.create_plot_html(plt.gcf(), f"bar_{column}") - plt.close() - - return f""" - {html} -Bar plot showing the distribution of {column}
- """ - except Exception as e: - return f"Could not generate bar plot for {column}: {str(e)}
" - - def _create_dynamic_scatter(self, data, x_col, y_col, target=False): - """Create a dynamic scatter plot for regression analysis""" - try: - x_values = data[x_col].dropna() - y_values = data[y_col].dropna() - common_indices = x_values.index.intersection(y_values.index) - if len(common_indices) < 2: - return f"Not enough valid data for scatter plot between {x_col} and {y_col}
" - - x_values = x_values.loc[common_indices].head(1000) # Limit to 1000 points for performance - y_values = y_values.loc[common_indices].head(1000) - - plt.figure(figsize=(8, 6)) - plt.scatter(x_values, y_values, color='teal', alpha=0.6) - plt.title(f'{y_col} vs {x_col}', fontsize=14) - plt.xlabel(x_col, fontsize=12) - plt.ylabel(y_col, fontsize=12) - - # Add range and correlation annotations - corr = np.corrcoef(x_values, y_values)[0, 1] if len(x_values) > 1 else 0 - stats_text = f'X Range: {x_values.min():.2f} to {x_values.max():.2f}\nY Range: {y_values.min():.2f} to {y_values.max():.2f}\nCorr: {corr:.2f}' - plt.text(0.95, 0.95, stats_text, transform=plt.gca().transAxes, ha='right', va='top', - bbox=dict(facecolor='white', alpha=0.8)) - - html = self.create_plot_html(plt.gcf(), f"scatter_{x_col}_{y_col}") - plt.close() - - return f""" - {html} -Scatter plot showing relationship between {x_col} and {y_col}
- """ - except Exception as e: - return f"Could not generate scatter plot for {x_col} vs {y_col}: {str(e)}
" + def _format_eda(self, result, target_column): + if not result or result.get('status') != 'success': + return "EDA not available.
" - def _create_dynamic_correlation_heatmap(self, correlation_matrix): - """Create a dynamic correlation heatmap""" - try: - corr_df = pd.DataFrame(correlation_matrix) - if corr_df.empty or len(corr_df.columns) < 2: - return "Not enough numeric features for correlation analysis
" - - plt.figure(figsize=(min(10, len(corr_df.columns) * 1.2), min(8, len(corr_df.columns) * 1))) - sns.heatmap( - corr_df, - annot=True, - cmap='coolwarm', - vmin=-1, - vmax=1, - center=0, - square=True, - fmt='.2f', - annot_kws={'size': max(8, 12 - len(corr_df.columns) // 2)}, - cbar_kws={'label': 'Correlation Coefficient'} - ) - plt.title('Correlation Matrix Heatmap', fontsize=14, pad=15) - plt.xticks(rotation=45, ha='right') - plt.yticks(rotation=0) - - html = self.create_plot_html(plt.gcf(), "correlation_heatmap") - plt.close() - - return f""" - {html} -Heatmap showing correlations between numeric features
- """ - except Exception as e: - return f"Could not generate correlation heatmap: {str(e)}
" - - def _format_eda_results(self, results, data, learning_type=None, target_column=None): - """Format EDA results with dynamic visualizations""" - if not results or results.get('status') != 'success' or data is None: - return "EDA information not available or no data loaded
" - - analysis = results.get('analysis', {}) - column_types = analysis.get('column_types', {}) - correlations = analysis.get('correlations', {}) + analysis = result.get('analysis', {}) + col_types = analysis.get('column_types', {}) + quality = analysis.get('data_quality_score', 'N/A') html = f""" -Numeric Features: {len(column_types.get('numeric', []))}
-Categorical Features: {len(column_types.get('categorical', []))}
-DateTime Features: {len(column_types.get('datetime', []))}
+โ Exploratory Data Analysis completed!
- """ + # Correlation heatmap + corr_data = analysis.get('correlations', {}).get('matrix', {}) + if corr_data and len(corr_data) > 1: + try: + corr_df = pd.DataFrame(corr_data) + fig, ax = plt.subplots(figsize=(min(10, len(corr_df)*1.2), + min(8, len(corr_df)))) + sns.heatmap(corr_df, annot=True, cmap='coolwarm', center=0, + vmin=-1, vmax=1, fmt='.2f', ax=ax, + annot_kws={'size': max(7, 11 - len(corr_df)//2)}) + ax.set_title('Correlation Matrix', fontsize=13) + plt.xticks(rotation=45, ha='right') + plt.tight_layout() + html += self.create_plot_html(fig, 'corr_heatmap') + except: + pass + + # Numeric distributions + if self.current_data is not None: + numeric_cols = col_types.get('numeric', [])[:3] + for col in numeric_cols: + try: + vals = self.current_data[col].dropna() + fig, ax = plt.subplots(figsize=(8, 4)) + sns.histplot(vals, bins=min(30, int(np.sqrt(len(vals)))), + kde=True, color='steelblue', ax=ax) + ax.set_title(f'Distribution of {col}', fontsize=12) + ax.set_xlabel(col) + ax.set_ylabel('Count') + plt.tight_layout() + html += self.create_plot_html(fig, f'hist_{col}') + except: + pass + + # Categorical bar plots + cat_cols = col_types.get('categorical', [])[:2] + for col in cat_cols: + try: + vc = self.current_data[col].value_counts().head(10) + fig, ax = plt.subplots(figsize=(8, 4)) + sns.barplot(x=vc.values, y=vc.index.astype(str), + palette='viridis', ax=ax) + ax.set_title(f'Top values in {col}', fontsize=12) + plt.tight_layout() + html += self.create_plot_html(fig, f'bar_{col}') + except: + pass + + # Target analysis + ta = analysis.get('target_analysis', {}) + if ta and target_column and target_column in self.current_data.columns: + try: + if ta['type'] == 'classification': + dist = self.current_data[target_column].value_counts() + fig, ax = plt.subplots(figsize=(7, 4)) + sns.barplot(x=dist.values, y=dist.index.astype(str), + palette='Set2', ax=ax) + ax.set_title(f'Target Distribution: {target_column}', fontsize=12) + plt.tight_layout() + html += self.create_plot_html(fig, 'target_dist') + else: + fig, ax = plt.subplots(figsize=(8, 4)) + sns.histplot(self.current_data[target_column].dropna(), + kde=True, color='coral', ax=ax) + ax.set_title(f'Target Distribution: {target_column}', fontsize=12) + plt.tight_layout() + html += self.create_plot_html(fig, 'target_dist') + except: + pass + + # Strong correlations + strong = analysis.get('correlations', {}).get('strong', []) + if strong: + html += f"๐ Strong Correlations Found ({len(strong)}):
Domain analysis information not available
" - - domain = results.get('detected_domain', 'general') - insights = results.get('insights', []) - recommendations = results.get('recommendations', []) + def _format_domain(self, result): + if not result: + return "No domain info.
" + domain = result.get('detected_domain', 'general') + insights = result.get('insights', []) + recommendations = result.get('recommendations', []) return f""" -โ Domain analysis completed!
""" - def _format_modeling_results(self, results, enable_deep_learning): - """Format modeling results with visualizations""" - if not results or results.get('status') != 'success': - return "Modeling information not available
" + def _format_modeling(self, result): + if not result or result.get('status') != 'success': + return f"Modeling failed: {result.get('error','Unknown')}
" - problem_type = results.get('problem_type', 'unknown') - best_model = results.get('best_model', 'Unknown') - model_results = results.get('results', {}) - feature_importance = results.get('feature_importance', {}) + problem_type = result.get('problem_type', 'unknown') + best_name = result.get('best_model', 'N/A') + results = result.get('results', {}) + feature_imp = result.get('feature_importance', {}) + # Results table html = f""" -| Model | -- {'Accuracy' if problem_type == 'classification' else 'RMSE'} - | -- {'F1 Score' if problem_type == 'classification' else 'Rยฒ Score'} - | -
|---|---|---|
| {model} | -{metric1:.3f} | -{metric2:.3f} | -
Deep learning models were evaluated but not included in final results due to complexity constraints.
-โ Model training and evaluation completed!
+Problem Type: {problem_type.title()}
| Model | """ + + if 'classification' in problem_type: + html += """Accuracy | +F1 Score | +Precision | +Recall | """ + else: + html += """RMSE | +MAE | +Rยฒ Score | """ - plt.figure(figsize=(8, max(6, len(features) * 0.5))) - sns.barplot(x=importances, y=features, palette='viridis') - plt.title('Feature Importance', fontsize=14) - plt.xlabel('Importance Score', fontsize=12) - plt.ylabel('Features', fontsize=12) + html += "
|---|---|---|---|---|---|---|---|
| {name} {'๐' if name == best_name else ''} | " + + if 'classification' in problem_type: + html += f"{metrics.get('accuracy','N/A')} | " + html += f"{metrics.get('f1_score','N/A')} | " + html += f"{metrics.get('precision','N/A')} | " + html += f"{metrics.get('recall','N/A')} | " + else: + html += f"{metrics.get('rmse','N/A')} | " + html += f"{metrics.get('mae','N/A')} | " + html += f"{metrics.get('r2_score','N/A')} | " - html = self.create_plot_html(plt.gcf(), "feature_importance") - plt.close() + html += "
Bar plot showing feature importance scores
- """ - except Exception as e: - return f"Could not generate feature importance plot: {str(e)}
" + # Feature importance plot + if feature_imp: + try: + features = list(feature_imp.keys())[:15] + importances = [feature_imp[f] for f in features] + fig, ax = plt.subplots(figsize=(8, max(5, len(features)*0.4))) + colors = ['#e74c3c' if f == features[0] else '#3498db' for f in features] + bars = ax.barh(features[::-1], importances[::-1], color=colors[::-1]) + ax.set_title(f'Feature Importance โ {best_name}', fontsize=13) + ax.set_xlabel('Importance Score') + for bar, imp in zip(bars, importances[::-1]): + ax.text(imp + 0.001, bar.get_y() + bar.get_height()/2, + f'{imp:.3f}', va='center', fontsize=9) + plt.tight_layout() + html += self.create_plot_html(fig, 'feature_importance') + except: + pass + + # Model comparison bar chart + if valid: + try: + names = list(valid.keys()) + if 'classification' in problem_type: + scores = [valid[n].get('accuracy', 0) for n in names] + metric_label = 'Accuracy' + else: + scores = [valid[n].get('r2_score', 0) for n in names] + metric_label = 'Rยฒ Score' + + fig, ax = plt.subplots(figsize=(10, 5)) + colors = ['#e74c3c' if n == best_name else '#3498db' for n in names] + bars = ax.bar(range(len(names)), scores, color=colors) + ax.set_xticks(range(len(names))) + ax.set_xticklabels(names, rotation=45, ha='right', fontsize=9) + ax.set_ylabel(metric_label) + ax.set_title(f'Model Comparison โ {metric_label}', fontsize=13) + for bar, score in zip(bars, scores): + ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.005, + f'{score:.3f}', ha='center', fontsize=8) + plt.tight_layout() + html += self.create_plot_html(fig, 'model_comparison') + except: + pass - def _format_unsupervised_results(self, data): - """Format unsupervised analysis results with dynamic clustering visualization""" - if data is None: - return "No data available for unsupervised analysis
" + return html - column_types = self.analyzer.detect_column_types(data) - numeric_cols = column_types['numeric'] + def _format_clustering(self): + if self.current_data is None: + return "No data available.
" - html = """ -Performed clustering analysis to identify natural groupings in the data.
- """ + html = "Unsupervised analysis โ performing KMeans clustering.
" + numeric_cols = self.current_data.select_dtypes(include=[np.number]).columns.tolist() if len(numeric_cols) >= 2: try: - # Perform KMeans clustering with dynamic number of clusters - X = data[numeric_cols].dropna().head(1000) - n_clusters = min(3, len(X) // 10) if len(X) > 10 else 2 - kmeans = KMeans(n_clusters=n_clusters, random_state=42) - clusters = kmeans.fit_predict(X) - - plt.figure(figsize=(8, 6)) - plt.scatter(X.iloc[:, 0], X.iloc[:, 1], c=clusters, cmap='viridis', alpha=0.6) - plt.title(f'Clustering: {numeric_cols[0]} vs {numeric_cols[1]}', fontsize=14) - plt.xlabel(numeric_cols[0], fontsize=12) - plt.ylabel(numeric_cols[1], fontsize=12) - - # Add cluster count annotation - plt.text(0.95, 0.95, f'Clusters: {n_clusters}', - transform=plt.gca().transAxes, ha='right', va='top', - bbox=dict(facecolor='white', alpha=0.8)) - - html += self.create_plot_html(plt.gcf(), "clustering_plot") - plt.close() - - html += f""" -- Scatter plot showing clusters based on {numeric_cols[0]} and {numeric_cols[1]} -
- """ + X = self.current_data[numeric_cols].dropna().head(1000) + scaler = StandardScaler() + X_scaled = scaler.fit_transform(X) + n_clusters = min(4, max(2, len(X) // 50)) + kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init=10) + labels = kmeans.fit_predict(X_scaled) + sil = round(silhouette_score(X_scaled, labels), 3) + + fig, ax = plt.subplots(figsize=(8, 6)) + scatter = ax.scatter(X.iloc[:, 0], X.iloc[:, 1], + c=labels, cmap='viridis', alpha=0.6) + plt.colorbar(scatter, ax=ax) + ax.set_title(f'KMeans Clustering (k={n_clusters}, silhouette={sil})', fontsize=12) + ax.set_xlabel(numeric_cols[0]) + ax.set_ylabel(numeric_cols[1]) + plt.tight_layout() + html += self.create_plot_html(fig, 'clustering') + html += f"Silhouette Score: {sil} (higher is better, max=1.0)
" except Exception as e: - html += f"Could not generate clustering plot: {str(e)}
" - else: - html += "Not enough numeric columns for clustering visualization
" + html += f"Could not generate clustering plot: {e}
" - html += """ -โ Unsupervised analysis completed!
-- Analysis Type: {learning_type} | Domain: {domain or 'General'} | - Deep Learning: {'Enabled' if enable_deep_learning else 'Disabled'} | - AutoML: {'Enabled' if enable_automl else 'Disabled'} +
+ Domain: {domain or 'General'} | + Completed: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} +
++ All model results are REAL โ trained on your actual data!
-Completed: {completion_time}
{msg}
โ Final results compiled!
- """ - return html - - def generate_report(self): - """Generate a downloadable HTML report with all results and visualizations""" - if not self.pipeline_results: - return self._create_error_html("No pipeline results available to generate report.") - - html = f""" - - - -