December 2022
This project explores the computational efficiency of conformal prediction methods for classification problems. Unlike traditional machine learning approaches that output single class predictions, conformal prediction generates prediction sets with guaranteed error control, making it particularly valuable for high-stakes applications.
I investigated two main approaches to conformal prediction: full conformal prediction and inductive conformal prediction, with a focus on their time complexity and practical performance trade-offs. The analysis was implemented in Python using custom code and established machine learning libraries.
The project methodology consisted of the following steps:
The experiments were run with multiple underlying machine learning models (random forest, support vector machines, and neural networks) to assess whether the complexity patterns held across different base algorithms.
The following code demonstrates the implementation of full and inductive conformal prediction algorithms:
import numpy as np
import time
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
class ConformalPredictor:
def __init__(self, base_model, alpha=0.05):
"""
Initialize conformal predictor
Parameters:
-----------
base_model : object
The underlying machine learning model with fit and predict methods
alpha : float
Significance level (default: 0.05)
"""
self.base_model = base_model
self.alpha = alpha
self.calibration_scores = None
def _nonconformity_score(self, model, X, y):
"""Calculate nonconformity scores for samples"""
# Get probability predictions for all classes
probas = model.predict_proba(X)
# Extract probabilities for true classes
n_samples = X.shape[0]
true_probas = np.array([probas[i, y[i]] for i in range(n_samples)])
# Nonconformity score is 1 - probability of true class
return 1 - true_probas
def fit_full_conformal(self, X, y):
"""Full conformal prediction calibration"""
n_samples = X.shape[0]
start_time = time.time()
# For each sample, fit model on rest and calculate nonconformity
self.calibration_scores = np.zeros(n_samples)
for i in range(n_samples):
# Leave-one-out
train_indices = [j for j in range(n_samples) if j != i]
X_train, y_train = X[train_indices], y[train_indices]
X_val, y_val = X[i:i+1], y[i:i+1]
# Train model
model = self.base_model.fit(X_train, y_train)
# Calculate nonconformity score
self.calibration_scores[i] = self._nonconformity_score(model, X_val, y_val)[0]
self.fit_time = time.time() - start_time
return self
def fit_inductive_conformal(self, X, y, calib_size=0.3):
"""Inductive conformal prediction calibration"""
start_time = time.time()
# Split data into proper training and calibration
X_train, X_calib, y_train, y_calib = train_test_split(
X, y, test_size=calib_size, random_state=42
)
# Train model on proper training set
self.model = self.base_model.fit(X_train, y_train)
# Calculate nonconformity scores on calibration set
self.calibration_scores = self._nonconformity_score(self.model, X_calib, y_calib)
self.fit_time = time.time() - start_time
return self
def predict(self, X):
"""Generate prediction sets"""
if self.calibration_scores is None:
raise ValueError("Fit the model first")
start_time = time.time()
# Calculate threshold based on significance level
threshold = np.percentile(self.calibration_scores, (1 - self.alpha) * 100)
# Get probabilities for each class
probas = self.model.predict_proba(X)
# Create prediction sets
n_samples = X.shape[0]
n_classes = probas.shape[1]
prediction_sets = []
for i in range(n_samples):
# Add classes to prediction set if nonconformity score <= threshold
pred_set = [j for j in range(n_classes) if 1 - probas[i, j] <= threshold]
prediction_sets.append(pred_set)
self.predict_time = time.time() - start_time
return prediction_sets
The code for measuring time complexity:
# Time complexity measurement
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
def measure_time_complexity(sample_sizes, method='inductive'):
"""Measure time complexity for different sample sizes"""
fit_times = []
predict_times = []
avg_set_sizes = []
for n in sample_sizes:
# Generate synthetic dataset
X, y = make_classification(n_samples=n, n_features=20, n_classes=3,
n_informative=15, random_state=42)
# Split into train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# Initialize model and conformal predictor
base_model = RandomForestClassifier(n_estimators=100, random_state=42)
cp = ConformalPredictor(base_model)
# Fit conformal predictor based on method
if method == 'full':
cp.fit_full_conformal(X_train, y_train)
else:
cp.fit_inductive_conformal(X_train, y_train)
# Generate prediction sets
pred_sets = cp.predict(X_test)
# Record times and set sizes
fit_times.append(cp.fit_time)
predict_times.append(cp.predict_time)
avg_set_sizes.append(np.mean([len(s) for s in pred_sets]))
return fit_times, predict_times, avg_set_sizes
# Run experiment
sample_sizes = [100, 500, 1000, 2000, 5000, 10000]
fcp_fit_times, fcp_predict_times, fcp_set_sizes = measure_time_complexity(sample_sizes, 'full')
icp_fit_times, icp_predict_times, icp_set_sizes = measure_time_complexity(sample_sizes, 'inductive')
# Plot results
plt.figure(figsize=(12, 8))
plt.subplot(2, 1, 1)
plt.plot(sample_sizes, fcp_fit_times, 'o-', label='Full CP (Fitting)')
plt.plot(sample_sizes, icp_fit_times, 's-', label='Inductive CP (Fitting)')
plt.xlabel('Sample Size')
plt.ylabel('Time (seconds)')
plt.title('Fitting Time vs. Sample Size')
plt.legend()
plt.grid(True)
plt.subplot(2, 1, 2)
plt.plot(sample_sizes, fcp_predict_times, 'o-', label='Full CP (Prediction)')
plt.plot(sample_sizes, icp_predict_times, 's-', label='Inductive CP (Prediction)')
plt.xlabel('Sample Size')
plt.ylabel('Time (seconds)')
plt.title('Prediction Time vs. Sample Size')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
The analysis revealed several key findings regarding the time complexity of conformal prediction:
Time complexity comparison between full and inductive conformal prediction:
[Time complexity graph would appear here]
Comparison of prediction set sizes for different methods:
[Prediction set size comparison would appear here]
This project provided valuable insights into the computational considerations for deploying conformal prediction methods:
This work contributes to the practical understanding of conformal prediction methods and provides concrete performance metrics to guide implementation choices in real-world machine learning systems where prediction sets are preferred over point predictions.