Scikit-Learn: The Complete ML Toolkit
Scikit-learn is one of the most widely used machine-learning libraries in Python. It provides a clean, consistent API for common stages of the ML workflow — from preprocessing and model training to evaluation and hyperparameter tuning. Once you understand its basic pattern, trying a different algorithm often requires only a small code change.
Scikit-learn in Simple Words
Think of scikit-learn as a toolbox for machine learning. You give it data, choose a model, let the model learn from examples, and then ask it to make predictions.
Prepare Data
Put your examples into X and the correct answers into y.
Choose Model
For example, LinearRegression or KNeighborsClassifier.
Learn
model.fit(X_train, y_train)
Predict
model.predict(X_test)
A tiny example
| Study hours | Marks |
|---|---|
| 1 | 40 |
| 2 | 50 |
| 3 | 60 |
| 4 | 70 |
From these examples, a simple regression model can learn the pattern and predict a mark for a new number of study hours.
Consistent API
fit() predict() score() for all models
40+ Algorithms
Regression, classification, clustering
Preprocessing
Scaling, encoding, imputation
Model Evaluation
Cross-val, metrics, GridSearch
The basic scikit-learn pattern
Create
model = Algorithm()
Choose the algorithm and its settings.
Fit
model.fit(X_train, y_train)
Learn patterns from the training examples.
Predict
model.predict(X_test)
Use the trained model on unseen examples.
Evaluate
accuracy_score(y_test, y_pred)
Compare predictions with the correct answers.
fit(), transform(), predict() — what is the difference?
| Method | Simple meaning | Example |
|---|---|---|
| fit() | Learn from data | Scaler learns mean; model learns a pattern |
| transform() | Change data using what was learned | Scale new values |
| predict() | Give an answer for new data | Predict Pass/Fail |
pip install scikit-learn import sklearn print(sklearn.__version__) # shows your installed version
1.x.x # exact version depends on your environment
1. Your First Complete ML Workflow
Start with one tiny example, then see a real built-in dataset
Start small: predict marks from study hours
Here the input X is study hours and the target y is marks.
from sklearn.linear_model import LinearRegression import numpy as np X = np.array([[1], [2], [3], [4]]) y = np.array([40, 50, 60, 70]) model = LinearRegression() model.fit(X, y) prediction = model.predict([[5]]) print(prediction[0])
80.0
Give examples.
Learn the pattern.
Ask about 5 hours.
Predicted marks = 80.
Now try a real built-in dataset: Iris
Why split the data?
all examples
model learns here
final check here
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# 1. Load dataset (150 iris flowers, 4 features, 3 species)
X, y = load_iris(return_X_y=True)
print(f"Dataset shape: {X.shape}") # (150, 4)
# 2. Split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42 # 80% train, 20% test
)
print(f"Training: {X_train.shape}, Test: {X_test.shape}")
# 3. Instantiate model
model = KNeighborsClassifier(n_neighbors=5)
# 4. Train
model.fit(X_train, y_train)
# 5. Predict
y_pred = model.predict(X_test)
# 6. Evaluate
acc = accuracy_score(y_test, y_pred)
print(f"Accuracy: {acc:.2%}")Dataset shape: (150, 4) Training: (120, 4), Test: (30, 4) Accuracy: 100.00%
2. Preprocessing — Prepare Data for Models
Most ML models require scaled, encoded, clean inputs. Scikit-learn makes this easy
Feature Scaling
Before scaling
Age: 20–60 Salary: ₹20,000–₹2,00,000
Salary numbers are much larger than age numbers.
After scaling
Both features are placed on comparable numerical scales.
This helps algorithms that are sensitive to distances or feature magnitude.
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import numpy as np
X = np.array([[1, 200], [2, 150], [3, 300], [4, 250]])
# StandardScaler: each feature is centred around 0 and scaled to unit variance
# Commonly useful for scale-sensitive models such as SVM, KNN and PCA
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
print("StandardScaler output:")
print(X_scaled.round(2))
print(f"Mean: {X_scaled.mean(axis=0).round(2)}") # should be [0, 0]
print(f"Std: {X_scaled.std(axis=0).round(2)}") # should be [1, 1]StandardScaler output: [[-1.34 -0.45] [-0.45 -1.34] [ 0.45 1.34] [ 1.34 0.45]] Mean: [0. 0.] Std: [1. 1.]
from sklearn.preprocessing import MinMaxScaler
# MinMaxScaler: maps each feature into the range [0, 1]
# Useful when you want features on the same bounded scale
minmax = MinMaxScaler()
X_minmax = minmax.fit_transform(X)
print("MinMaxScaler output (all values 0–1):")
print(X_minmax.round(2))MinMaxScaler output (all values 0–1): [[0. 0.33] [0.33 0. ] [0.67 1. ] [1. 0.67]]
Encoding Categorical Features
LabelEncoder is intended for the target y (the answer you want to predict), not for ordinary input columns in X. For nominal input features such as city names, use OneHotEncoder or a suitable alternative.from sklearn.preprocessing import LabelEncoder
# LabelEncoder is useful for target labels (y)
species = ['setosa', 'versicolor', 'virginica', 'setosa']
le = LabelEncoder()
y_encoded = le.fit_transform(species)
print("Encoded target:", y_encoded)
print("Classes:", le.classes_)
print("Decode:", le.inverse_transform([0, 2]))Encoded target: [0 1 2 0] Classes: ['setosa' 'versicolor' 'virginica'] Decode: ['setosa' 'virginica']
# One-Hot Encoding — creates binary columns for nominal input features
from sklearn.preprocessing import OneHotEncoder
import numpy as np
cities = ['Delhi', 'Mumbai', 'Pune', 'Delhi', 'Mumbai']
cities_2d = np.array(cities).reshape(-1, 1)
ohe = OneHotEncoder(sparse_output=False)
X_ohe = ohe.fit_transform(cities_2d)
print("One-Hot Encoded:")
print(X_ohe)
print("Feature names:", ohe.get_feature_names_out(['City']))One-Hot Encoded: [[1. 0. 0.] [0. 1. 0.] [0. 0. 1.] [1. 0. 0.] [0. 1. 0.]] Feature names: ['City_Delhi' 'City_Mumbai' 'City_Pune']
Handling Missing Values
from sklearn.impute import SimpleImputer
import numpy as np
X = np.array([[1, 2], [np.nan, 4], [7, np.nan], [4, 3]])
# Mean imputation for numerical columns
imputer = SimpleImputer(strategy='mean') # or 'median', 'most_frequent'
X_filled = imputer.fit_transform(X)
print("After imputation:")
print(X_filled)After imputation: [[1. 2. ] [4. 4. ] ← NaN replaced with column mean (1+7+4)/3 = 4 [7. 3. ] ← NaN replaced with column mean (2+4+3)/3 = 3 [4. 3. ]]
3. Common Algorithms — Same API, Different Models
The beauty of scikit-learn: swap one algorithm for another by changing just one line
from sklearn.linear_model import LinearRegression, LogisticRegression, Ridge
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Load dataset
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test) # ← NEVER fit on test data!
# Try multiple classifiers — identical API for all!
classifiers = {
'Logistic Regression': LogisticRegression(max_iter=1000),
'Decision Tree': DecisionTreeClassifier(max_depth=5, random_state=42),
'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
'SVM': SVC(kernel='rbf'),
'KNN': KNeighborsClassifier(n_neighbors=5),
'Naive Bayes': GaussianNB(),
'Gradient Boosting': GradientBoostingClassifier(n_estimators=100, random_state=42),
}
print(f"{'Algorithm':<25} {'Accuracy':>10}")
print("-" * 37)
for name, clf in classifiers.items():
clf.fit(X_train_s, y_train)
acc = clf.score(X_test_s, y_test)
print(f"{name:<25} {acc:>10.2%}")Algorithm Accuracy ------------------------------------- Logistic Regression 97.37% Decision Tree 94.74% Random Forest 96.49% SVM 98.25% KNN 94.74% Naive Bayes 96.49% Gradient Boosting 95.61% # Example output; exact scores can vary slightly across library versions.
4. Model Evaluation — Going Beyond Accuracy
Accuracy alone can be misleading. Use the right metric for your problem
from sklearn.metrics import (
accuracy_score, precision_score, recall_score, f1_score,
confusion_matrix, classification_report, roc_auc_score
)
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"Precision: {precision_score(y_test, y_pred):.4f}")
print(f"Recall: {recall_score(y_test, y_pred):.4f}")
print(f"F1-Score: {f1_score(y_test, y_pred):.4f}")
print(f"ROC-AUC: {roc_auc_score(y_test, clf.predict_proba(X_test)[:,1]):.4f}")
print("\nConfusion Matrix:")
print(confusion_matrix(y_test, y_pred))
print("\nFull Classification Report:")
print(classification_report(y_test, y_pred, target_names=['Malignant','Benign']))Accuracy: 0.9649
Precision: 0.9589
Recall: 0.9859
F1-Score: 0.9722
ROC-AUC: 0.9953
Confusion Matrix:
[[40 3]
[ 1 70]]
Full Classification Report:
precision recall f1-score support
Malignant 0.98 0.93 0.95 43
Benign 0.96 0.99 0.97 71
accuracy 0.96 114
macro avg 0.97 0.96 0.96 114
weighted avg 0.97 0.96 0.96 114
# Example output; exact values can vary slightly across versions.5. Cross-Validation — Reliable Model Evaluation
A single train/test split can be lucky or unlucky. Cross-validation repeats the evaluation on different folds
5-fold cross-validation — one simple picture
Each fold gets one turn as the test fold. The five scores are then summarized.
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
import numpy as np
X, y = load_iris(return_X_y=True)
clf = RandomForestClassifier(n_estimators=100, random_state=42)
# 5-fold cross validation
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(clf, X, y, cv=cv, scoring='accuracy')
print("Fold scores:", scores.round(4))
print(f"Mean: {scores.mean():.4f}")
print(f"Std: {scores.std():.4f} ← lower = more consistent")
print(f"Rough spread (mean ± 2×std): {scores.mean():.2%} ± {2*scores.std():.2%}")Fold scores: [0.9667 0.9667 0.9333 0.9667 0.9000] Mean: 0.9467 Std: 0.0267 ← lower means the fold scores vary less Rough spread (mean ± 2×std): 94.67% ± 5.33% # This is a simple spread summary, not a formal confidence interval.
6. Hyperparameter Tuning with GridSearchCV
Automatically find the best hyperparameter combination using cross-validation
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
# Define the search grid
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 5, 10],
'min_samples_split': [2, 5],
}
rf = RandomForestClassifier(random_state=42)
# GridSearchCV tries every combination with 5-fold CV
# 3 × 3 × 2 = 18 combinations × 5 folds = 90 model fits
grid_search = GridSearchCV(
rf, param_grid, cv=5, scoring='accuracy',
n_jobs=-1, verbose=1
)
grid_search.fit(X, y)
print("Best parameters:", grid_search.best_params_)
print(f"Best CV accuracy: {grid_search.best_score_:.4f}")
# Use the best model directly
best_model = grid_search.best_estimator_Fitting 5 folds for each of 18 candidates, totalling 90 fits
Best parameters: {...}
Best CV accuracy: 0.96...
# The exact winner can vary with scikit-learn version and CV details.
# Always trust grid_search.best_params_ from your own run.7. ColumnTransformer — Treat Different Columns Differently
Scale numeric columns and encode categorical columns in one clean preprocessing step
Imagine this small dataset
| Age | Salary | City |
|---|---|---|
| 25 | 50000 | Delhi |
StandardScaler
OneHotEncoder
model-ready features
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
preprocessor = ColumnTransformer([
('numbers', StandardScaler(), ['Age', 'Salary']),
('city', OneHotEncoder(handle_unknown='ignore'), ['City']),
])
# fit_transform() learns the preprocessing rules and transforms the data
X_ready = preprocessor.fit_transform(df)8. Pipeline — Chain Preprocessing + Model Together
Pipelines keep preprocessing and modelling together and help prevent data leakage
fill missing values
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Define pipeline steps: preprocessing → model
pipeline = Pipeline([
('imputer', SimpleImputer(strategy='median')), # Step 1: Fill NaN
('scaler', StandardScaler()), # Step 2: Scale
('model', RandomForestClassifier(n_estimators=100, random_state=42)), # Step 3
])
# fit() applies all steps in sequence to training data only
pipeline.fit(X_train, y_train)
# predict() applies preprocessing then prediction automatically
print(f"Test accuracy: {pipeline.score(X_test, y_test):.4f}")
# Cross-validate the entire pipeline (no leakage!)
cv_scores = cross_val_score(pipeline, X, y, cv=5)
print(f"CV accuracy: {cv_scores.mean():.4f} ± {cv_scores.std():.4f}")Test accuracy: 0.9649 CV accuracy: 0.9561 ± 0.0228 # Example output; exact values can vary slightly across versions.
🎯 Scikit-Learn Quick Reference
Data Splitting
train_test_split(X, y, test_size=0.2)cross_val_score(model, X, y, cv=5)Preprocessing
StandardScaler().fit_transform(X)MinMaxScaler().fit_transform(X)LabelEncoder().fit_transform(y)SimpleImputer(strategy='mean').fit_transform(X)Metrics
accuracy_score(y_true, y_pred)f1_score(y_true, y_pred)confusion_matrix(y_true, y_pred)roc_auc_score(y_true, y_prob)Tuning
GridSearchCV(model, param_grid, cv=5)RandomizedSearchCV(model, param_dist, n_iter=20)Pipeline([('scaler', ...), ('model', ...)])Common Scikit-learn Questions
What is scikit-learn mainly used for?
It is commonly used for classical machine-learning tasks such as preprocessing, regression, classification, clustering, model evaluation and hyperparameter tuning.
What is the difference between fit() and predict()?
fit() learns from training data. predict() uses the learned model to produce answers for new data.
Why should preprocessing be fitted only on training data?
If information from the test data is used while learning preprocessing rules, the evaluation can become unrealistically optimistic. This is called data leakage.
When should I use a Pipeline?
Use a Pipeline when preprocessing and modelling should always run together. It keeps the workflow reproducible and is especially useful with cross-validation and tuning.