Classifier-adjusted density estimation (CADE) detects outliers by generating synthetic records from feature distributions, labeling real and synthetic records, and training a binary classifier to separate them. section 3.2.5
CADE generates each feature independently from a uniform distribution. The resulting data is usually less realistic than normally distributed or more carefully estimated samples, making separation easier. section 3.2.5 section 11.2.2
A practical CADE workflow involves:
- Generate a synthetic dataset with the same number of records as the real dataset. section 3.2.5
- Train a classifier on combined real and synthetic records, using the real-versus-fake label as the target. section 3.2.5
- Tune synthetic-data generation and classifier complexity until classification is accurate but imperfect. section 3.2.5
- Treat real records classified as synthetic as candidate outliers, rather than automatically meaningful anomalies. section 3.2.5
Breast-cancer records
Using the scikit-learn breast-cancer dataset, a decision tree correctly identified 544 of 569 real records and 561 of 569 synthetic records. The 25 real records predicted as synthetic became candidate outliers. section 3.2.5
CADE’s central limitation is synthetic-data quality: independently generated features can match individual distributions while losing relationships between features. More faithful histograms or KDEs improve marginal resemblance, but preserving associations requires sequential generation methods. section 11.2.2
Listing 3.7 Predicting real vs. synthetic data
import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import confusion_matrix
from sklearn.tree import export_text
np.random.seed(0)
data = load_breast_cancer() #1
data_df = pd.DataFrame(data.data, columns=data.feature_names)
data_df['Real'] = True
synth_df = pd.DataFrame() #2
for col_name in data_df.columns:
mean = data_df[col_name].mean()
stddev = data_df[col_name].std()
synth_df[col_name] = np.random.normal(
loc=mean, scale=stddev, size=len(data_df))
synth_df['Real'] = False
train_df = pd.concat([data_df, synth_df])
clf = DecisionTreeClassifier(
max_depth=7, random_state=0) #3
clf.fit(train_df.drop(columns=['Real']), train_df['Real'])
pred = clf.predict(train_df.drop(columns=['Real']))
confusion_matrix(train_df['Real'], pred) #4
Inspect the compact Python implementation that combines real and synthetic records, trains a decision tree, and evaluates real-versus-synthetic predictions. section 3.2.5
