QuAcc/quacc/experiments/run.py

125 lines
4.0 KiB
Python

import itertools
import os
import quapy as qp
from ClassifierAccuracy.util.plotting import plot_diagonal
from quapy.protocol import UPP
from quacc.dataset import save_dataset_stats
from quacc.experiments.generators import (
any_missing,
gen_acc_measure,
gen_bin_datasets,
gen_CAP,
gen_CAP_cont_table,
gen_classifiers,
gen_multi_datasets,
gen_tweet_datasets,
)
from quacc.experiments.report import TestReport
from quacc.experiments.util import (
fit_method,
predictionsCAP,
predictionsCAPcont_table,
prevs_from_prot,
true_acc,
)
PROBLEM = "binary"
ORACLE = False
basedir = PROBLEM + ("-oracle" if ORACLE else "")
if PROBLEM == "binary":
qp.environ["SAMPLE_SIZE"] = 1000
NUM_TEST = 1000
gen_datasets = gen_bin_datasets
elif PROBLEM == "multiclass":
qp.environ["SAMPLE_SIZE"] = 250
NUM_TEST = 1000
gen_datasets = gen_multi_datasets
elif PROBLEM == "tweet":
qp.environ["SAMPLE_SIZE"] = 100
NUM_TEST = 1000
gen_datasets = gen_tweet_datasets
for (cls_name, h), (dataset_name, (L, V, U)) in itertools.product(
gen_classifiers(), gen_datasets()
):
print(f"training {cls_name} in {dataset_name}")
h.fit(*L.Xy)
# test generation protocol
test_prot = UPP(
U, repeats=NUM_TEST, return_type="labelled_collection", random_state=0
)
# compute some stats of the dataset
save_dataset_stats(f"dataset_stats/{dataset_name}.json", test_prot, L, V)
# precompute the actual accuracy values
true_accs = {}
for acc_name, acc_fn in gen_acc_measure():
true_accs[acc_name] = [true_acc(h, acc_fn, Ui) for Ui in test_prot()]
# instances of ClassifierAccuracyPrediction are bound to the evaluation measure, so they
# must be nested in the acc-for
for acc_name, acc_fn in gen_acc_measure():
print(f"\tfor measure {acc_name}")
for method_name, method in gen_CAP(h, acc_fn, with_oracle=ORACLE):
report = TestReport(cls_name, acc_name, dataset_name, method_name)
if os.path.exists(report.path(basedir)):
print(f"\t\t{method_name}-{acc_name} exists, skipping")
continue
print(f"\t\t{method_name} computing...")
method, t_train = fit_method(method, V)
estim_accs, t_test_ave = predictionsCAP(method, test_prot, ORACLE)
test_prevs = prevs_from_prot(test_prot)
report.add_result(
test_prevs=test_prevs,
true_accs=true_accs[acc_name],
estim_accs=estim_accs,
t_train=t_train,
t_test_ave=t_test_ave,
).save_json(basedir)
# instances of CAPContingencyTable instead are generic, and the evaluation measure can
# be nested to the predictions to speed up things
for method_name, method in gen_CAP_cont_table(h):
if not any_missing(basedir, cls_name, dataset_name, method_name):
print(
f"\t\tmethod {method_name} has all results already computed. Skipping."
)
continue
print(f"\t\tmethod {method_name} computing...")
method, t_train = fit_method(method, V)
estim_accs_dict, t_test_ave = predictionsCAPcont_table(
method, test_prot, gen_acc_measure, ORACLE
)
for acc_name in estim_accs_dict.keys():
report = TestReport(cls_name, acc_name, dataset_name, method_name)
report.add_result(
true_accs=true_accs[acc_name],
estim_accs=estim_accs,
t_train=t_train,
t_test_ave=t_test_ave,
).save_json(basedir)
print()
# generate diagonal plots
print("generating plots")
for (cls_name, _), (acc_name, _) in itertools.product(
gen_classifiers(), gen_acc_measure()
):
plot_diagonal(basedir, cls_name, acc_name)
for dataset_name, _ in gen_datasets(only_names=True):
plot_diagonal(basedir, cls_name, acc_name, dataset_name=dataset_name)
print("generating tables")
# gen_tables(basedir, datasets=[d for d, _ in gen_datasets(only_names=True)])