Healthcare: Breast cancer classification using eigenkit
Why this problem matters
Breast cancer is one of the most common cancers in the world. Reliable tools that support classification help clinicians to detect high-risk cases earlier, to decide which diagnostic tests come first, and to improve the outcomes of treatment.
A research demonstration, not a medical tool
This example shows how to use the library on a public dataset. It is not a medical device and has not been validated for any clinical use. Do not use it, or a model trained the same way, to diagnose or treat anyone.
Dataset
This example uses the Wisconsin Breast Cancer dataset, which is available in
eigenkit.datasets under the name breast_cancer_wisconsin.
Our approach: Hybrid Quantum-Classical Classification (HQNC)
In this example, we train the hybrid quantum neural network classifier (HQNC) of eigenkit to separate two classes (benign and malignant tumours), and we measure the quality of its predictions.
Import libraries
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.metrics import accuracy_score, classification_report, f1_score
from eigenkit.datasets import STYLE_COLORS, load_dataset, rc_params
from eigenkit import HQNC
Loading the selected dataset
# Load and split dataset into train/test subsets
data = load_dataset("breast_cancer_wisconsin", split=True, test_size=0.2, random_state=42)
X_train, y_train = data["X_train"], data["y_train"]
X_test, y_test = data["X_test"], data["y_test"]
# Convert to NumPy arrays for stable downstream processing
X_train = np.asarray(X_train, dtype=np.float32)
X_test = np.asarray(X_test, dtype=np.float32)
y_train = np.asarray(y_train)
y_test = np.asarray(y_test)
print("Train shape:", X_train.shape, y_train.shape)
print("Test shape:", X_test.shape, y_test.shape)
print("Class counts (train):", dict(zip(*np.unique(y_train, return_counts=True))))
# Reduce dimensionality to keep quantum circuit width practical
n_components = 8
pca = PCA(n_components=n_components, random_state=42)
X_train_pca = pca.fit_transform(X_train).astype(np.float32)
X_test_pca = pca.transform(X_test).astype(np.float32)
print("Train shape after PCA:", X_train_pca.shape)
print("Test shape after PCA:", X_test_pca.shape)
print("Explained variance ratio:", round(float(pca.explained_variance_ratio_.sum()), 4))
Train shape: (455, 30) (455,)
Test shape: (114, 30) (114,)
Class counts (train): {np.int64(0): np.int64(170), np.int64(1): np.int64(285)}
Train shape after PCA: (455, 8)
Test shape after PCA: (114, 8)
Explained variance ratio: 1.0
Model creation and training
# Configure HQNC classifier
model = HQNC(
in_features=n_components,
n_qubits=n_components,
depth=2,
n_classes=len(np.unique(y_train)),
layer_type="Basic",
variational_type="strong",
basis="Y",
lr=0.001,
optimizer="adam",
epochs=150,
batch_size=32,
random_state=42,
)
# Fit model on transformed training features
model.fit(X_train_pca, y_train)
print("Training complete. Last epoch loss:", round(float(model.train_losses_[-1]), 6))
HQNC training | Epoch 1/150 | loss=0.751814 | elapsed=0.6s | eta=95.4s
HQNC training | Epoch 2/150 | loss=0.744411 | elapsed=1.3s | eta=94.6s
HQNC training | Epoch 3/150 | loss=0.743520 | elapsed=1.9s | eta=94.2s
...
HQNC training | Epoch 149/150 | loss=0.210164 | elapsed=96.0s | eta=0.6s
HQNC training | Epoch 150/150 | loss=0.208010 | elapsed=96.6s | eta=0.0s
Training complete. Last epoch loss: 0.20801
Evaluation
# Predict on the held-out test split
y_pred = model.predict(X_test_pca)
# Report core classification quality metrics
acc = accuracy_score(y_test, y_pred)
macro_f1 = f1_score(y_test, y_pred, average="macro")
weighted_f1 = f1_score(y_test, y_pred, average="weighted")
print(f"Accuracy: {acc:.4f}")
print(f"Macro F1: {macro_f1:.4f}")
print(f"Weighted F1: {weighted_f1:.4f}")
print("Classification report:")
print(classification_report(y_test, y_pred, digits=4, zero_division=0))
Accuracy: 0.9298
Macro F1: 0.9221
Weighted F1: 0.9285
Classification report:
precision recall f1-score support
0 0.9722 0.8333 0.8974 42
1 0.9103 0.9861 0.9467 72
accuracy 0.9298 114
macro avg 0.9412 0.9097 0.9221 114
weighted avg 0.9331 0.9298 0.9285 114
Plotting results
# Visualize training dynamics across epochs
with matplotlib.rc_context(rc_params(theme="light")):
plt.figure(figsize=(7, 4))
plt.plot(model.train_losses_, color=STYLE_COLORS[0], label="train loss")
plt.xlabel("Epoch")
plt.ylabel("Cross-entropy loss")
plt.title("HQNC training curve on breast_cancer_wisconsin")
plt.legend()
plt.tight_layout()
plt.show()

Takeaway
An HQNC with 8 qubits and depth=2 receives 8 components from a principal
component analysis (PCA) of the original 30 features. After 150 epochs, it
reaches an accuracy of 0.9298 and a macro F1 score of 0.9221 on the test split
of 114 samples. The PCA step is what keeps the circuit narrow: with one qubit for
each input feature, the circuit would need 30 qubits. The width of the circuit
and the number of components are the two settings to change first. They balance
the cost of the simulation against how much of the variance of the data reaches
the model.