classification_pipeline.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. """
  2. Complete classification pipeline example with preprocessing, model training,
  3. hyperparameter tuning, and evaluation.
  4. """
  5. import numpy as np
  6. import pandas as pd
  7. from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
  8. from sklearn.preprocessing import StandardScaler, OneHotEncoder
  9. from sklearn.impute import SimpleImputer
  10. from sklearn.compose import ColumnTransformer
  11. from sklearn.pipeline import Pipeline
  12. from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
  13. from sklearn.linear_model import LogisticRegression
  14. from sklearn.metrics import (
  15. classification_report, confusion_matrix, roc_auc_score,
  16. accuracy_score, precision_score, recall_score, f1_score
  17. )
  18. import warnings
  19. warnings.filterwarnings('ignore')
  20. def create_preprocessing_pipeline(numeric_features, categorical_features):
  21. """
  22. Create a preprocessing pipeline for mixed data types.
  23. Parameters:
  24. -----------
  25. numeric_features : list
  26. List of numeric feature column names
  27. categorical_features : list
  28. List of categorical feature column names
  29. Returns:
  30. --------
  31. ColumnTransformer
  32. Preprocessing pipeline
  33. """
  34. # Numeric preprocessing
  35. numeric_transformer = Pipeline(steps=[
  36. ('imputer', SimpleImputer(strategy='median')),
  37. ('scaler', StandardScaler())
  38. ])
  39. # Categorical preprocessing
  40. categorical_transformer = Pipeline(steps=[
  41. ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
  42. ('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
  43. ])
  44. # Combine transformers
  45. preprocessor = ColumnTransformer(
  46. transformers=[
  47. ('num', numeric_transformer, numeric_features),
  48. ('cat', categorical_transformer, categorical_features)
  49. ]
  50. )
  51. return preprocessor
  52. def train_and_evaluate_model(X, y, numeric_features, categorical_features,
  53. test_size=0.2, random_state=42):
  54. """
  55. Complete pipeline: preprocess, train, tune, and evaluate a classifier.
  56. Parameters:
  57. -----------
  58. X : DataFrame or array
  59. Feature matrix
  60. y : Series or array
  61. Target variable
  62. numeric_features : list
  63. List of numeric feature names
  64. categorical_features : list
  65. List of categorical feature names
  66. test_size : float
  67. Proportion of data for testing
  68. random_state : int
  69. Random seed
  70. Returns:
  71. --------
  72. dict
  73. Dictionary containing trained model, predictions, and metrics
  74. """
  75. # Split data with stratification
  76. X_train, X_test, y_train, y_test = train_test_split(
  77. X, y, test_size=test_size, stratify=y, random_state=random_state
  78. )
  79. print(f"Training set size: {len(X_train)}")
  80. print(f"Test set size: {len(X_test)}")
  81. print(f"Class distribution in training: {pd.Series(y_train).value_counts().to_dict()}")
  82. # Create preprocessor
  83. preprocessor = create_preprocessing_pipeline(numeric_features, categorical_features)
  84. # Define models to compare
  85. models = {
  86. 'Logistic Regression': Pipeline([
  87. ('preprocessor', preprocessor),
  88. ('classifier', LogisticRegression(max_iter=1000, random_state=random_state))
  89. ]),
  90. 'Random Forest': Pipeline([
  91. ('preprocessor', preprocessor),
  92. ('classifier', RandomForestClassifier(n_estimators=100, random_state=random_state))
  93. ]),
  94. 'Gradient Boosting': Pipeline([
  95. ('preprocessor', preprocessor),
  96. ('classifier', GradientBoostingClassifier(n_estimators=100, random_state=random_state))
  97. ])
  98. }
  99. # Compare models using cross-validation
  100. print("\n" + "="*60)
  101. print("Model Comparison (5-Fold Cross-Validation)")
  102. print("="*60)
  103. cv_results = {}
  104. for name, model in models.items():
  105. scores = cross_val_score(model, X_train, y_train, cv=5, scoring='accuracy')
  106. cv_results[name] = scores.mean()
  107. print(f"{name:20s}: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
  108. # Select best model based on CV
  109. best_model_name = max(cv_results, key=cv_results.get)
  110. best_model = models[best_model_name]
  111. print(f"\nBest model: {best_model_name}")
  112. # Hyperparameter tuning for best model
  113. if best_model_name == 'Random Forest':
  114. param_grid = {
  115. 'classifier__n_estimators': [100, 200],
  116. 'classifier__max_depth': [10, 20, None],
  117. 'classifier__min_samples_split': [2, 5]
  118. }
  119. elif best_model_name == 'Gradient Boosting':
  120. param_grid = {
  121. 'classifier__n_estimators': [100, 200],
  122. 'classifier__learning_rate': [0.01, 0.1],
  123. 'classifier__max_depth': [3, 5]
  124. }
  125. else: # Logistic Regression
  126. param_grid = {
  127. 'classifier__C': [0.1, 1.0, 10.0],
  128. 'classifier__penalty': ['l2']
  129. }
  130. print("\n" + "="*60)
  131. print("Hyperparameter Tuning")
  132. print("="*60)
  133. grid_search = GridSearchCV(
  134. best_model, param_grid, cv=5, scoring='accuracy',
  135. n_jobs=-1, verbose=0
  136. )
  137. grid_search.fit(X_train, y_train)
  138. print(f"Best parameters: {grid_search.best_params_}")
  139. print(f"Best CV score: {grid_search.best_score_:.4f}")
  140. # Evaluate on test set
  141. tuned_model = grid_search.best_estimator_
  142. y_pred = tuned_model.predict(X_test)
  143. y_pred_proba = tuned_model.predict_proba(X_test)
  144. print("\n" + "="*60)
  145. print("Test Set Evaluation")
  146. print("="*60)
  147. # Calculate metrics
  148. accuracy = accuracy_score(y_test, y_pred)
  149. precision = precision_score(y_test, y_pred, average='weighted')
  150. recall = recall_score(y_test, y_pred, average='weighted')
  151. f1 = f1_score(y_test, y_pred, average='weighted')
  152. print(f"Accuracy: {accuracy:.4f}")
  153. print(f"Precision: {precision:.4f}")
  154. print(f"Recall: {recall:.4f}")
  155. print(f"F1-Score: {f1:.4f}")
  156. # ROC AUC (if binary classification)
  157. if len(np.unique(y)) == 2:
  158. roc_auc = roc_auc_score(y_test, y_pred_proba[:, 1])
  159. print(f"ROC AUC: {roc_auc:.4f}")
  160. print("\n" + "="*60)
  161. print("Classification Report")
  162. print("="*60)
  163. print(classification_report(y_test, y_pred))
  164. print("\n" + "="*60)
  165. print("Confusion Matrix")
  166. print("="*60)
  167. print(confusion_matrix(y_test, y_pred))
  168. # Feature importance (if available)
  169. if hasattr(tuned_model.named_steps['classifier'], 'feature_importances_'):
  170. print("\n" + "="*60)
  171. print("Top 10 Most Important Features")
  172. print("="*60)
  173. feature_names = tuned_model.named_steps['preprocessor'].get_feature_names_out()
  174. importances = tuned_model.named_steps['classifier'].feature_importances_
  175. feature_importance_df = pd.DataFrame({
  176. 'feature': feature_names,
  177. 'importance': importances
  178. }).sort_values('importance', ascending=False).head(10)
  179. print(feature_importance_df.to_string(index=False))
  180. return {
  181. 'model': tuned_model,
  182. 'y_test': y_test,
  183. 'y_pred': y_pred,
  184. 'y_pred_proba': y_pred_proba,
  185. 'metrics': {
  186. 'accuracy': accuracy,
  187. 'precision': precision,
  188. 'recall': recall,
  189. 'f1': f1
  190. }
  191. }
  192. # Example usage
  193. if __name__ == "__main__":
  194. # Load example dataset
  195. from sklearn.datasets import load_breast_cancer
  196. # Load data
  197. data = load_breast_cancer()
  198. X = pd.DataFrame(data.data, columns=data.feature_names)
  199. y = data.target
  200. # For demonstration, treat all features as numeric
  201. numeric_features = X.columns.tolist()
  202. categorical_features = []
  203. print("="*60)
  204. print("Classification Pipeline Example")
  205. print("Dataset: Breast Cancer Wisconsin")
  206. print("="*60)
  207. # Run complete pipeline
  208. results = train_and_evaluate_model(
  209. X, y, numeric_features, categorical_features,
  210. test_size=0.2, random_state=42
  211. )
  212. print("\n" + "="*60)
  213. print("Pipeline Complete!")
  214. print("="*60)