Přeskočit na hlavní obsah
Tento projekt je v betě. Našel jsi chybu? Otevřít issue na GitHubu. Máš otázku nebo nápad? Zeptej se v Discussions — rádi si poslechneme tvou zpětnou vazbu!
Jaká je kvalita překladu na této stránce?

Klasifikace úvěrového rizika pomocí Kipu Quantum Rimay Quantum Feature Extraction

poznámka

Qiskit Functions jsou experimentální funkce dostupná pouze uživatelům plánů IBM Quantum® Premium Plan, Flex Plan a On-Prem (přes IBM Quantum Platform API) Plan. Jsou ve stavu předběžného vydání (preview) a mohou se změnit.

Odhad využití: 2 minuty na procesoru Nighthawk r2. (POZNÁMKA: Jde pouze o odhad. Skutečná doba běhu se může lišit.)

Výsledky učení​

  • Připrav tabulková data s kategoriálními a numerickými sloupci pro Qiskit Function Rimay.

  • Natrénuj kvantové mapování příznaků na trénovacích datech a v tomtéž běhu namapuj testovací data.

  • Trénuj klasické modely na kvantově transformovaných příznacích, samotných i v kombinaci s původními příznaky.

  • Porovnej výsledky s čistě klasickým základním modelem.

Předpoklady​

Než začneš s tímto tutoriálem, měl/a bys být obeznámen/a s následujícími tématy:

Pozadí​

Mnoho problémů strojového učení v průmyslu pracuje s malými nebo středně velkými tabulkovými datovými sadami, kde přidání dalších dat není možné a přesnost modelu stagnuje. Typickým příkladem je hodnocení úvěrového rizika. Věřitel používá několik desítek atributů, aby rozhodl, zda žadatel úvěr pravděpodobně splatí.

Rimay, Qiskit Function od společnosti Kipu Quantum, přidává do takového pipeline krok kvantového předzpracování. Implementuje algoritmus digitalizované kontradiabatické kvantové extrakce příznaků [1]. Každý vstupní příznak se mapuje na jeden qubit. Hodnoty příznaků a vzájemná informace mezi příznaky určují lokální pole a vazby Hamiltoniánu spinového skla. Kontradiabatická dynamika pak vyvíjí kvantový systém směrem k jeho stavům s nízkou energií a jedno- a dvoučásticové střední hodnoty změřené na konci se stávají novými, kvantově transformovanými příznaky. Tyto příznaky zachycují nelineární korelace mezi vstupy a můžeš je předat libovolnému klasickému modelu.

Pipeline with Rimay inserted between the train-test split and the classical machine learning model

Tento tutoriál používá německou úvěrovou datovou sadu z OpenML [2] s 1000 žadateli a 20 atributy k trénování klasifikátoru náhodného lesa. Nejprve vytvoříš klasický základní model, poté pošleš data do Rimay a nakonec natrénuješ stejný typ modelu na kvantově transformovaných příznacích, samotných i v kombinaci s původními příznaky.

Požadavky​

Než začneš s tímto tutoriálem, ujisti se, že máš nainstalované následující balíčky:

  • Klient IBM Quantum Compute (pip install qiskit-ibm-runtime)

  • Qiskit Functions (pip install qiskit-ibm-catalog)

  • scikit-learn (pip install scikit-learn)

  • pandas (pip install pandas)

  • Matplotlib (pip install matplotlib)

Potřebuješ také přístup k funkci Rimay z katalogu Qiskit Functions.

Nastavení​

Importuj balíčky a definuj dvě pomocné funkce: jednu, která trénuje náhodný les, a druhou, která počítá metriky používané v celém tutoriálu.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"matplotlib": "matplotlib", "numpy": "numpy", "pandas": "pandas", "qiskit_ibm_catalog": "qiskit-ibm-catalog", "sklearn": "scikit-learn"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from qiskit_ibm_catalog import QiskitFunctionsCatalog
from sklearn.datasets import fetch_openml
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import (
accuracy_score,
f1_score,
precision_score,
recall_score,
roc_auc_score,
)
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder

def train_random_forest(x, y, n_estimators, max_depth):
"""Train a random forest classifier with fixed hyperparameters."""
model = RandomForestClassifier(
n_estimators=n_estimators,
max_depth=max_depth,
min_samples_split=5,
min_samples_leaf=1,
max_features="sqrt",
random_state=42,
n_jobs=-1,
)
return model.fit(x, y)

def evaluate(model, x, y):
"""Return the classification metrics of a trained model on a test set."""
y_pred = model.predict(x)
y_proba = model.predict_proba(x)[:, 1]
return {
"Accuracy": accuracy_score(y, y_pred),
"AUC": roc_auc_score(y, y_proba),
"F1 score": f1_score(y, y_pred),
"Precision": precision_score(y, y_pred),
"Recall": recall_score(y, y_pred),
}

Nastavení přihlašovacích údajů IBM Quantum​

Ověř se pomocí svého API klíče IBM Quantum Platform, načti funkci Rimay a vyber nejméně vytížený kvantový procesor dostupný ve své instanci.

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
rimay = catalog.load("kipu-quantum/rimay")

backend = catalog.least_busy(operational=True, simulator=False)
print(backend.name, backend.num_qubits)
ibm_fez 156

Krok 1: Mapování klasických vstupů na kvantový problém​

Rimay mapuje každý numerický vstupní příznak na jeden qubit, takže prvním krokem je převést surovou tabulku na numerické příznaky.

Načtení datové sady​

Načti německou úvěrovou datovou sadu přímo z OpenML. Sloupec class obsahuje štítek: good pro žadatele, kteří úvěr splatili, a bad pro ty, kteří ho nesplatili.

df = fetch_openml(data_id=31, as_frame=True).frame
print(df.shape)
df.head()
(1000, 21)
checking_status duration credit_history \
0 <0 6 critical/other existing credit
1 0<=X<200 48 existing paid
2 no checking 12 critical/other existing credit
3 <0 42 existing paid
4 <0 24 delayed previously

purpose credit_amount savings_status employment \
0 radio/tv 1169 no known savings >=7
1 radio/tv 5951 <100 1<=X<4
2 education 2096 <100 4<=X<7
3 furniture/equipment 7882 <100 4<=X<7
4 new car 4870 <100 1<=X<4

installment_commitment personal_status other_parties ... \
0 4 male single none ...
1 2 female div/dep/mar none ...
2 2 male single none ...
3 2 male single guarantor ...
4 3 male single none ...

property_magnitude age other_payment_plans housing existing_credits \
0 real estate 67 none own 2
1 real estate 22 none own 1
2 real estate 49 none own 1
3 life insurance 45 none for free 1
4 no known property 53 none for free 2

job num_dependents own_telephone foreign_worker class
0 skilled 1 yes yes good
1 skilled 1 none yes bad
2 unskilled resident 2 none yes good
3 skilled 2 none yes good
4 skilled 2 none yes bad

[5 rows x 21 columns]

Kódování příznaků​

Převeď štítek na binární hodnotu a proveď one-hot kódování 13 kategoriálních sloupců. Kód vypouští první kategorii každého sloupce, aby se předešlo redundantním příznakům, což vede k 48 numerickým příznakům.

y = (df["class"] == "good").astype(int)

features = df.drop(columns="class")
categorical_cols = [
col for col in features.columns if features[col].dtype.name == "category"
]
encoder = OneHotEncoder(
sparse_output=False, handle_unknown="ignore", drop="first"
)
encoded = pd.DataFrame(
encoder.fit_transform(features[categorical_cols]),
columns=encoder.get_feature_names_out(categorical_cols),
index=features.index,
)
x = pd.concat([features.drop(columns=categorical_cols), encoded], axis=1)
print(f"{x.shape[1]} features")
48 features

Rozdělení na trénovací a testovací sady​

Ponech 20 % žadatelů stranou jako testovací sadu. Stratifikované rozdělení udržuje podíl dobrých a špatných úvěrů v obou sadách stejný.

x_train, x_test, y_train, y_test = train_test_split(
x, y, test_size=0.2, random_state=42, stratify=y
)
print(f"Training set: {x_train.shape}, test set: {x_test.shape}")
Training set: (800, 48), test set: (200, 48)

Vytvoření klasického základního modelu​

Natrénuj náhodný les na klasických příznacích. V kroku 4 s jeho metrikami porovnáš kvantově transformované příznaky.

baseline = train_random_forest(
x_train, y_train, n_estimators=500, max_depth=12
)
results = {"Classical": evaluate(baseline, x_test, y_test)}
pd.DataFrame(results).T
Accuracy AUC F1 score Precision Recall
Classical 0.765 0.781071 0.845902 0.781818 0.921429

Nahrání dat do Rimay​

Rimay čte své vstupy ze souborů CSV, které do funkce nahraješ. Příznaky a štítky jdou do oddělených souborů. Nahraješ také testovací sadu, aby ji Rimay namapovalo stejným mapováním, jaké natrénuje na trénovací sadě.

x_train.to_csv("x_train.csv", index=False)
y_train.to_csv("y_train.csv", index=False)
x_test.to_csv("x_test.csv", index=False)

for file_name in ("x_train.csv", "y_train.csv", "x_test.csv"):
catalog.file_upload(file_name, rimay)

Krok 2: Optimalizace problému pro spuštění na kvantovém hardwaru​

Rimay sestaví a transpiluje obvody pro procesor, který vybereš, takže není třeba nic ručně optimalizovat. Zadej počet shotů na obvod v rámci následujících omezení:

  • Každý příznak potřebuje jeden qubit, takže procesor musí mít alespoň tolik qubitů, kolik má datová sada příznaků.

  • Rimay spouští jeden obvod na řádek, trénovací a testovací řádky dohromady. Jedna úloha může požadovat nejvýše 10 milionů spuštění, takže počet řádků krát shots musí zůstat v tomto rozpočtu.

Zkontroluj obě omezení před odesláním úlohy.

poznámka

Úloha musí také skončit do 24 hodin, včetně doby, kterou její obvody čekají ve frontě, jinak je zastavena bez výsledku.

shots = 5000

n_rows = len(x_train) + len(x_test)
n_features = x_train.shape[1]
print(f"Qubits needed: {n_features} of {backend.num_qubits} available")
print(f"Executions: {n_rows * shots:,} of 10,000,000 allowed")
Qubits needed: 48 of 156 available
Executions: 5,000,000 of 10,000,000 allowed

Výpočet velikosti funkce​

Každá úloha běží s určitou velikostí funkce, S, M nebo L, která určuje výpočetní prostředky, na nichž běží. U Rimay závisí velikost na počtu řádků, které úloha mapuje, trénovacích a testovacích dohromady. Pokud požaduješ příliš malou velikost, úloha selže s chybou 4600. Velikosti a jejich limity najdeš v části Function sizes v průvodci Rimay.

Následující buňka definuje kalkulátor velikosti. Běží na tvém počítači, čte pouze data, která mu předáš, a nic neodesílá.

from os import PathLike
from typing import Any, Literal, Sequence, Sized

Size = Literal["S", "M", "L"]

# Upper bounds (inclusive) in samples.
_SMALL = 2_999
_MEDIUM = 9_999

FIT_TRANSFORM, TRANSFORM, DELETE = "fit-transform", "transform", "delete"

# Which positions of input_file hold samples, per mode. The labels in
# y_train submit no circuits of their own, so they are not counted.
SAMPLE_POSITIONS = {FIT_TRANSFORM: (0, 2), TRANSFORM: (0,)}

def calculate_function_size(problem: Sequence[Sized], **kwargs: Any) -> Size:
"""Return the size ("S", "M" or "L") required to run the function."""
metrics = _measure(problem, **kwargs)
if _is_small(metrics):
return "S"
if _is_medium(metrics):
return "M"
return "L"

def _measure(problem: Sequence[Sized], **kwargs: Any) -> dict:
"""The samples the job submits."""
return {"samples": count_samples(problem, kwargs.get("mode"))}

def count_samples(problem: Sequence[Sized], mode: Any) -> int:
"""Rows across the data sets of ``problem`` that carry samples."""
if mode == DELETE:
return 0
if mode not in SAMPLE_POSITIONS:
raise ValueError(f"cannot size mode {mode!r}")
if _is_name(problem) or (
isinstance(problem, (list, tuple))
and any(_is_name(data) for data in problem)
):
raise TypeError(
"pass the data, not the file name: read each input_file, e.g. with "
"pandas.read_csv, and pass the data sets in input_file order"
)
if not isinstance(problem, (list, tuple)):
raise TypeError(
"pass a list of data sets in input_file order, e.g. [x_train, y_train], "
f"not a single {type(problem).__name__}"
)
return sum(
len(problem[i]) for i in SAMPLE_POSITIONS[mode] if i < len(problem)
)

def _is_name(value: Any) -> bool:
"""A file name or path rather than data."""
return isinstance(value, (str, bytes, PathLike))

def _is_small(metrics: dict) -> bool:
"""Determine if the metrics fit T-size 'S'."""
return metrics["samples"] <= _SMALL

def _is_medium(metrics: dict) -> bool:
"""Determine if the metrics fit T-size 'M'."""
return metrics["samples"] <= _MEDIUM

Předej datové sady ve stejném pořadí jako soubory v input_file spolu s režimem běhu:

size = calculate_function_size(
[x_train, y_train, x_test], mode="fit-transform"
)
print(size)
S

Krok 3: Spuštění pomocí primitiv Qiskit​

Spusť Rimay v režimu fit-transform. Natrénuje kvantové mapování příznaků na x_train.csv a y_train.csv a namapuje s ním trénovací i testovací sadu. Pořadí souborů v input_file je důležité. Uveď trénovací příznaky, trénovací štítky a poté volitelné testovací příznaky. Jako function_size předej velikost, kterou jsi vypočítal/a.

job = rimay.run(
mode="fit-transform",
input_file=[
"x_train.csv",
"y_train.csv",
"x_test.csv",
], # This order matters
backend_name=backend.name,
shots=shots,
function_size=size,
)
print(job.job_id)
de5094df-bb17-4924-9605-d6196a4aa999

Sledování úlohy​

Během běhu kontroluj stav úlohy. job.result() blokuje, dokud úloha neskončí.

print(job.status())
INITIALIZING
result = job.result()
print(result["output_files"])
['de5094df-bb17-4924-9605-d6196a4aa999_xq_train.csv', 'de5094df-bb17-4924-9605-d6196a4aa999_xq_test.csv']

Výsledek obsahuje mapping_id, který identifikuje mapování natrénované tímto během. V tomto tutoriálu ho nepotřebuješ, protože testovací sada byla namapována ve stejném běhu. Toto ID si zaznamenej, pokud chceš později mapovat nové řádky pomocí mode="transform". Je to jediný způsob, jak získat natrénované mapování, a bez něj musíš natrénovat a zaplatit nové. Mapování je sestaveno pro rozložení qubitů tohoto procesoru, takže pozdější běh transform musí předat stejné backend_name.

mapping_id = result["mapping_id"]

Krok 4: Následné zpracování a vrácení výsledku v požadovaném klasickém formátu​

Stažení kvantově transformovaných příznaků​

Stáhni soubory, které úloha zapsala, pomocí názvů v output_files. Každý název začíná ID úlohy, takže soubory tohoto běhu zůstanou dostupné i po pozdějších bězích. Předej target_name, aby se každý soubor uložil pod vlastním názvem.

train_file, test_file = result["output_files"]
for file_name in (train_file, test_file):
catalog.file_download(file_name, rimay, target_name=file_name)

xq_train = pd.read_csv(train_file).to_numpy()
xq_test = pd.read_csv(test_file).to_numpy()
print(f"Quantum-transformed features: {xq_train.shape[1]}")
586kiB [00:00, 1.13MiB/s]
147kiB [00:00, 336kiB/s]
Quantum-transformed features: 99

Trénování na kvantově transformovaných příznacích​

Natrénuj náhodný les pouze na kvantově transformovaných příznacích.

quantum = train_random_forest(
xq_train, y_train, n_estimators=900, max_depth=15
)
results["Quantum"] = evaluate(quantum, xq_test, y_test)

Trénování na kombinaci klasických a kvantových příznaků​

Spoj původní a kvantově transformované příznaky a natrénuj stejný model na této kombinaci.

xh_train = np.hstack([x_train.to_numpy(), xq_train])
xh_test = np.hstack([x_test.to_numpy(), xq_test])

hybrid = train_random_forest(
xh_train, y_train, n_estimators=900, max_depth=15
)
results["Hybrid"] = evaluate(hybrid, xh_test, y_test)

Porovnání výsledků​

Porovnej tři modely na testovací sadě.

comparison = pd.DataFrame(results).T
print(comparison.round(3))

comparison[["Accuracy", "AUC", "F1 score"]].T.plot.bar(rot=0, figsize=(8, 4))
plt.ylim(0.5, 1.0)
plt.ylabel("Score on the test set")
plt.title("Random forest on classical, quantum, and hybrid features")
plt.show()
Accuracy AUC F1 score Precision Recall
Classical 0.765 0.781 0.846 0.782 0.921
Quantum 0.730 0.784 0.827 0.750 0.921
Hybrid 0.730 0.791 0.825 0.756 0.907

Output of the previous code cell

AUC měří, jak dobře model řadí dobré úvěry nad špatné, nezávisle na prahu rozhodnutí, což z něj dělá nejinformativnější metriku na této nevyvážené datové sadě (70 % dobrých úvěrů). V benchmarcích Kipu Quantum dosáhly samotné kvantově transformované příznaky AUC podobné klasickému základnímu modelu a hybridní model, který kombinuje obojí, dosáhl nejvyššího AUC a skóre F1. Kvantově transformované příznaky tedy přidávají informaci, kterou samotné klasické příznaky neposkytují.

Úklid (volitelné)​

Natrénované mapování zůstává dostupné, dokud ho nesmažeš. Pokud s ním nechceš mapovat další data, smaž ho. Smazání neprovádí žádnou kvantovou práci, nespotřebuje čas QPU a nelze ho vrátit zpět.

# rimay.run(mode="delete", mapping_id=mapping_id).result()
{'output_files': [],
'mode': 'delete',
'deleted': True,
'mapping_id': 'eUCy4EnZM7G9jYo5b2Pu-TuCXK7zX_wPTT67g9J1dVE',
'metadata': {'version': '0.6.0', 'resource_usage': {}}}

Závěr​

Čeho jsi dosáhl/a​

V tomto tutoriálu jsi dosáhl/a následujícího:

  1. Připravil/a jsi reálnou datovou sadu úvěrového rizika s kategoriálními a numerickými atributy pro kvantovou extrakci příznaků.

  2. Vytvořil/a jsi klasický základní model náhodného lesa.

  3. Použil/a jsi Rimay k natrénování kvantového mapování příznaků na kvantovém hardwaru a k namapování trénovací a testovací sady v jednom běhu.

  4. Natrénoval/a jsi stejný model na kvantově transformovaných i na kombinovaných příznacích a porovnal/a jsi je se základním modelem.

Hlavní poznatky​

  • Rimay zapadá do existujícího pipeline strojového učení jako jeden dodatečný krok předzpracování. Zachováš si svou přípravu dat i svůj klasický model.

  • Počet qubitů omezuje počet vstupních příznaků a počet řádků krát shots omezuje velikost jedné úlohy.

  • Jako výchozí volbu používej kvantově transformované příznaky v kombinaci s původními příznaky, protože model může využít obojí.

Další kroky​

Doporučení
  • Přečti si průvodce Rimay, abys poznal/a všechny vstupy, mapoval/a nová data pomocí mode="transform" a viděl/a další benchmarky.
  • Přečti si, jak byla kvantová extrakce příznaků použita při klasifikaci satelitních snímků [3].

Reference​

[1] Simen, A., et al. (2025). Digitized Counterdiabatic Quantum Feature Extraction. arXiv preprint arXiv:2510.13807.

[2] Hofmann, H. (1994). Statlog (German Credit Data). OpenML dataset 31.

[3] Zhang, Q., et al. (2026). Quantum-enhanced satellite image classification. arXiv preprint arXiv:2602.18350.