Benchmark only with best experiments results

This commit is contained in:
2022-03-02 12:06:03 +01:00
parent a4ddcda5d6
commit 15b46fcc21
3 changed files with 172 additions and 129 deletions

View File

@@ -5,7 +5,6 @@ import json
import abc import abc
import shutil import shutil
import subprocess import subprocess
from tqdm import tqdm
import xlsxwriter import xlsxwriter
from Experiments import Datasets, BestResults from Experiments import Datasets, BestResults
from Utils import Folders, Files, Symbols, BEST_ACCURACY_STREE, TextColor from Utils import Folders, Files, Symbols, BEST_ACCURACY_STREE, TextColor
@@ -456,49 +455,56 @@ class SQL(BaseReport):
class Benchmark: class Benchmark:
@staticmethod def __init__(self, score):
def get_result_file_name(score): self._score = score
return os.path.join(Folders.results, Files.exreport(score)) self._results = []
self._models = []
self._report = {}
self._datasets = set()
@staticmethod def get_result_file_name(self):
def _process_dataset(results, data): return os.path.join(Folders.results, Files.exreport(self._score))
model = data["model"]
for record in data["results"]:
dataset = record["dataset"]
if (model, dataset) in results:
if record["score"] > results[model, dataset][0]:
results[model, dataset] = (
record["score"],
record["score_std"],
)
else:
results[model, dataset] = (
record["score"],
record["score_std"],
)
@staticmethod def compile_results(self):
def compile_results(score): summary = Summary()
summary.acquire(given_score=self._score)
self._models = summary.get_models()
for model in self._models:
best = summary.best_result(
criterion="model", value=model, score=self._score
)
file_name = os.path.join(Folders.results, best["file"])
with open(file_name) as fi:
experiment = json.load(fi)
for result in experiment["results"]:
dataset = result["dataset"]
record = {
"model": model,
"dataset": dataset,
"score": result["score"],
"score_std": result["score_std"],
"file_name": file_name,
}
self._results.append(record)
if model not in self._report:
self._report[model] = {}
self._report[model][dataset] = record
self._datasets.add(dataset)
self._datasets = sorted(self._datasets)
def save_results(self):
# build Files.exreport # build Files.exreport
result_file_name = Benchmark.get_result_file_name(score) result_file_name = self.get_result_file_name()
results = {}
init_suffix, end_suffix = Files.results_suffixes(score=score)
all_files = list(os.walk(Folders.results))
for root, _, files in tqdm(all_files, desc="files"):
for name in files:
if name.startswith(init_suffix) and name.endswith(end_suffix):
file_name = os.path.join(root, name)
with open(file_name) as fp:
data = json.load(fp)
Benchmark._process_dataset(results, data)
with open(result_file_name, "w") as f: with open(result_file_name, "w") as f:
f.write(f"classifier, dataset, {score}, stdev\n") f.write(f"classifier, dataset, {self._score}, stdev, file_name\n")
for (model, dataset), (accuracy, stdev) in results.items(): for record in self._results:
f.write(f"{model}, {dataset}, {accuracy}, {stdev}\n") f.write(
f"{record['model']}, {record['dataset']}, "
f"{record['score']}, {record['score_std']}, "
f"{record['file_name']}\n"
)
@staticmethod def exreport(self):
def exreport(score):
def end_message(message, file): def end_message(message, file):
length = 100 length = 100
print("*" * length) print("*" * length)
@@ -515,74 +521,67 @@ class Benchmark:
os.remove(Files.exreport_pdf) os.remove(Files.exreport_pdf)
except FileNotFoundError: except FileNotFoundError:
pass pass
except OSError as e: except OSError as os_error:
print("Error: %s : %s" % (Folders.report, e.strerror)) print("Error: %s : %s" % (Folders.report, os_error.strerror))
# Compute Friedman & Holm Tests # Compute Friedman & Holm Tests
fout = open( fout = open(
os.path.join(Folders.results, Files.exreport_output(score)), "w" os.path.join(Folders.results, Files.exreport_output(self._score)),
"w",
) )
ferr = open( ferr = open(
os.path.join(Folders.results, Files.exreport_err(score)), "w" os.path.join(Folders.results, Files.exreport_err(self._score)), "w"
) )
result = subprocess.run( result = subprocess.run(
["Rscript", os.path.join(Folders.src, Files.benchmark_r), score], [
"Rscript",
os.path.join(Folders.src, Files.benchmark_r),
self._score,
],
stdout=fout, stdout=fout,
stderr=ferr, stderr=ferr,
) )
fout.close() fout.close()
ferr.close() ferr.close()
if result.returncode != 0: if result.returncode != 0:
end_message("Error computing benchmark", Files.exreport_err(score)) end_message(
"Error computing benchmark", Files.exreport_err(self._score)
)
else: else:
end_message("Benchmark Ok", Files.exreport_output(score)) end_message("Benchmark Ok", Files.exreport_output(self._score))
Files.open(Files.exreport_pdf) Files.open(Files.exreport_pdf)
@staticmethod def report(self):
def build_results(score):
# Build results data structure
file_name = Benchmark.get_result_file_name(score)
results = {}
with open(file_name) as f:
data = f.read().splitlines()
data = data[1:]
for line in data:
model, dataset, accuracy, stdev = line.split(", ")
if model not in results:
results[model] = {}
results[model][dataset] = (accuracy, stdev)
return results
@staticmethod
def report(score):
def show(results):
datasets = results[list(results)[0]]
print(f"{'Dataset':30s} ", end="") print(f"{'Dataset':30s} ", end="")
lines = "=" * 30 + " " lines = "=" * 30 + " "
for model in results: for model in self._models:
print(f"{model:^13s} ", end="") print(f"{model:^13s} ", end="")
lines += "=" * 13 + " " lines += "=" * 13 + " "
print(f"\n{lines}") print(f"\n{lines}")
for dataset, _ in datasets.items(): for dataset in self._datasets:
print(f"{dataset:30s} ", end="") print(f"{dataset:30s} ", end="")
for model in results: for model in self._models:
print(f"{float(results[model][dataset][0]):.5f}±", end="") result = self._report[model][dataset]
print(f"{float(results[model][dataset][1]):.3f} ", end="") print(f"{float(result['score']):.5f}±", end="")
print(f"{float(result['score_std']):.3f} ", end="")
print("") print("")
d_name = next(iter(self._datasets))
print(f"\n{'Model':30s} {'File Name':75s} Score")
print("=" * 30 + " " + "=" * 75 + " ========")
for model in self._models:
file_name = self._report[model][d_name]["file_name"]
report = StubReport(file_name)
report.report()
print(f"{model:^30s} {file_name:75s} {report.score:8.5f}")
print(f"* Score is: {score}") def get_excel_file_name(self):
show(Benchmark.build_results(score)) return os.path.join(
Folders.exreport, Files.exreport_excel(self._score)
)
@staticmethod def excel(self):
def get_excel_file_name(score): book = xlsxwriter.Workbook(self.get_excel_file_name())
return os.path.join(Folders.exreport, Files.exreport_excel(score))
@staticmethod
def excel(score):
results = Benchmark.build_results(score)
book = xlsxwriter.Workbook(Benchmark.get_excel_file_name(score))
sheet = book.add_worksheet("Benchmark") sheet = book.add_worksheet("Benchmark")
normal = book.add_format({"font_size": 14}) normal = book.add_format({"font_size": 14})
bold = book.add_format({"bold": True, "font_size": 14})
decimal = book.add_format({"num_format": "0.000000", "font_size": 14}) decimal = book.add_format({"num_format": "0.000000", "font_size": 14})
merge_format = book.add_format( merge_format = book.add_format(
{ {
@@ -592,22 +591,30 @@ class Benchmark:
"font_size": 14, "font_size": 14,
} }
) )
merge_format_normal = book.add_format(
{
"valign": "vcenter",
"font_size": 14,
}
)
row = row_init = 4 row = row_init = 4
def header(): def header():
nonlocal row nonlocal row
sheet.merge_range(0, 0, 1, 0, "Benchmark of Models", merge_format) sheet.merge_range(0, 0, 1, 0, "Benchmark of Models", merge_format)
sheet.write(1, 2, f"Score is {score}", bold) sheet.merge_range(
0, 1, 1, 2, f"Score is {self._score}", merge_format
)
sheet.set_row(1, 20) sheet.set_row(1, 20)
# Set columns width # Set columns width
sheet.set_column(0, 0, 40) sheet.set_column(0, 0, 40)
for column in range(2 * len(results)): for column in range(2 * len(self._results)):
sheet.set_column(column + 1, column + 1, 15) sheet.set_column(column + 1, column + 1, 15)
# Set report header # Set report header
# Merge 2 rows # Merge 2 rows
sheet.merge_range(row, 0, row + 1, 0, "Dataset", merge_format) sheet.merge_range(row, 0, row + 1, 0, "Dataset", merge_format)
column = 1 column = 1
for model in results: for model in self._models:
# Merge 2 columns # Merge 2 columns
sheet.merge_range( sheet.merge_range(
row, column, row, column + 1, model, merge_format row, column, row, column + 1, model, merge_format
@@ -615,42 +622,73 @@ class Benchmark:
column += 2 column += 2
row += 1 row += 1
column = 1 column = 1
for _ in range(len(results)): for _ in range(len(self._results)):
sheet.write(row, column, "Score", merge_format) sheet.write(row, column, "Score", merge_format)
sheet.write(row, column + 1, "Stdev", merge_format) sheet.write(row, column + 1, "Stdev", merge_format)
column += 2 column += 2
def body(): def body():
nonlocal row nonlocal row
datasets = results[list(results)[0]] for dataset in self._datasets:
for dataset, _ in datasets.items():
row += 1 row += 1
sheet.write(row, 0, f"{dataset:30s}", normal) sheet.write(row, 0, f"{dataset:30s}", normal)
column = 1 column = 1
for model in results: for model in self._models:
sheet.write( sheet.write(
row, row,
column, column,
float(results[model][dataset][0]), float(self._report[model][dataset]["score"]),
decimal, decimal,
) )
column += 1 column += 1
sheet.write( sheet.write(
row, row,
column, column,
float(results[model][dataset][1]), float(self._report[model][dataset]["score_std"]),
decimal, decimal,
) )
column += 1 column += 1
def footer(): def footer():
nonlocal row
for c in range(row_init, row + 1): for c in range(row_init, row + 1):
sheet.set_row(c, 20) sheet.set_row(c, 20)
def models_files():
nonlocal row
row += 2
# Set report header
# Merge 2 rows
sheet.merge_range(row, 0, row + 1, 0, "Model", merge_format)
sheet.merge_range(row, 1, row + 1, 5, "File", merge_format)
sheet.merge_range(row, 6, row + 1, 6, "Score", merge_format)
row += 1
d_name = next(iter(self._datasets))
for model in self._models:
file_name = self._report[model][d_name]["file_name"]
report = StubReport(file_name)
report.report()
row += 1
sheet.write(
row,
0,
model,
normal,
)
sheet.merge_range(
row, 1, row, 5, file_name, merge_format_normal
)
sheet.write(
row,
6,
report.score,
decimal,
)
header() header()
body() body()
footer() footer()
models_files()
book.close() book.close()
@@ -667,6 +705,7 @@ class StubReport(BaseReport):
def footer(self, accuracy: float) -> None: def footer(self, accuracy: float) -> None:
self.accuracy = accuracy self.accuracy = accuracy
self.score = accuracy / BEST_ACCURACY_STREE
class Summary: class Summary:
@@ -674,8 +713,12 @@ class Summary:
self.results = Files().get_all_results() self.results = Files().get_all_results()
self.data = [] self.data = []
self.datasets = {} self.datasets = {}
self.models = set()
def acquire(self) -> None: def get_models(self):
return self.models
def acquire(self, given_score="any") -> None:
"""Get all results""" """Get all results"""
for result in self.results: for result in self.results:
( (
@@ -686,6 +729,8 @@ class Summary:
time, time,
stratified, stratified,
) = Files().split_file_name(result) ) = Files().split_file_name(result)
if given_score in ("any", score):
self.models.add(model)
report = StubReport(os.path.join(Folders.results, result)) report = StubReport(os.path.join(Folders.results, result))
report.report() report.report()
entry = dict( entry = dict(
@@ -697,7 +742,7 @@ class Summary:
time=time, time=time,
stratified=stratified, stratified=stratified,
file=result, file=result,
metric=report.accuracy / BEST_ACCURACY_STREE, metric=report.score,
duration=report.duration, duration=report.duration,
) )
self.datasets[result] = report.lines self.datasets[result] = report.lines

View File

@@ -27,10 +27,11 @@ def parse_arguments():
(score, excel) = parse_arguments() (score, excel) = parse_arguments()
benchmark = Benchmark() benchmark = Benchmark(score)
benchmark.compile_results(score) benchmark.compile_results()
benchmark.report(score) benchmark.save_results()
benchmark.exreport(score) benchmark.report()
benchmark.exreport()
if excel: if excel:
benchmark.excel(score) benchmark.excel()
Files.open(benchmark.get_excel_file_name(score)) Files.open(benchmark.get_excel_file_name())

View File

@@ -2,7 +2,7 @@
import argparse import argparse
import os import os
from Results import Summary, StubReport from Results import Summary, StubReport
from Utils import EnvDefault, Folders, BEST_ACCURACY_STREE from Utils import EnvDefault, Folders
"""Check best results of two models giving scores and win-tie-loose results """Check best results of two models giving scores and win-tie-loose results
""" """
@@ -66,12 +66,9 @@ for result1, result2 in zip(report_1.lines, report_2.lines):
tie += 1 tie += 1
print(f"{'Model':<20} {'File':<70} {'Score':<10} Win Tie Loose") print(f"{'Model':<20} {'File':<70} {'Score':<10} Win Tie Loose")
print("=" * 20 + " " + "=" * 70 + " " + "=" * 10 + " === === =====") print("=" * 20 + " " + "=" * 70 + " " + "=" * 10 + " === === =====")
print( print(f"{model1:<20} {best_1['file']:<70} {report_1.score:10.5f}")
f"{model1:<20} {best_1['file']:<70} "
f"{report_1.accuracy / BEST_ACCURACY_STREE:10.5f}"
)
print( print(
f"{model2:<20} {best_2['file']:<70} " f"{model2:<20} {best_2['file']:<70} "
f"{report_2.accuracy / BEST_ACCURACY_STREE:10.5f} " f"{report_2.score:10.5f} "
f"{win:3d} {tie:3d} {loose:5d}" f"{win:3d} {tie:3d} {loose:5d}"
) )