Refactor coverage report generation
Add some tests to reach 99%
This commit is contained in:
@@ -22,3 +22,28 @@ TEST_CASE("Fit and Score", "[A2DE]")
|
||||
REQUIRE(clf.getNumberOfEdges() == 756);
|
||||
REQUIRE(clf.getNotes().size() == 0);
|
||||
}
|
||||
TEST_CASE("Test score with predict_voting", "[A2DE]")
|
||||
{
|
||||
auto raw = RawDatasets("glass", true);
|
||||
auto clf = bayesnet::A2DE(true);
|
||||
auto hyperparameters = nlohmann::json{
|
||||
{"predict_voting", true},
|
||||
};
|
||||
clf.setHyperparameters(hyperparameters);
|
||||
clf.fit(raw.Xv, raw.yv, raw.features, raw.className, raw.states);
|
||||
REQUIRE(clf.score(raw.Xv, raw.yv) == Catch::Approx(0.82243).epsilon(raw.epsilon));
|
||||
hyperparameters["predict_voting"] = false;
|
||||
clf.setHyperparameters(hyperparameters);
|
||||
clf.fit(raw.Xv, raw.yv, raw.features, raw.className, raw.states);
|
||||
REQUIRE(clf.score(raw.Xv, raw.yv) == Catch::Approx(0.83178).epsilon(raw.epsilon));
|
||||
}
|
||||
TEST_CASE("Test graph", "[A2DE]")
|
||||
{
|
||||
auto raw = RawDatasets("iris", true);
|
||||
auto clf = bayesnet::A2DE();
|
||||
clf.fit(raw.Xv, raw.yv, raw.features, raw.className, raw.states);
|
||||
auto graph = clf.graph();
|
||||
REQUIRE(graph.size() == 78);
|
||||
REQUIRE(graph[0] == "digraph BayesNet {\nlabel=<BayesNet A2DE_0>\nfontsize=30\nfontcolor=blue\nlabelloc=t\nlayout=circo\n");
|
||||
REQUIRE(graph[1] == "class [shape=circle, fontcolor=red, fillcolor=lightblue, style=filled ] \n");
|
||||
}
|
||||
|
@@ -75,4 +75,12 @@ TEST_CASE("Metrics Test", "[Metrics]")
|
||||
REQUIRE(resultv == resultsMST.at({ file_name, i }));
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_CASE("Select all features ordered by Mutual Information", "[Metrics]")
|
||||
{
|
||||
auto raw = RawDatasets("iris", true);
|
||||
bayesnet::Metrics metrics(raw.dataset, raw.features, raw.className, raw.classNumStates);
|
||||
auto kBest = metrics.SelectKBestWeighted(raw.weights, true, 0);
|
||||
REQUIRE(kBest.size() == raw.features.size());
|
||||
REQUIRE(kBest == std::vector<int>({ 1, 0, 3, 2 }));
|
||||
}
|
@@ -20,7 +20,7 @@
|
||||
#include "bayesnet/ensembles/BoostAODE.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
const std::string ACTUAL_VERSION = "1.0.5";
|
||||
const std::string ACTUAL_VERSION = "1.0.5.1";
|
||||
|
||||
TEST_CASE("Test Bayesian Classifiers score & version", "[Models]")
|
||||
{
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <string>
|
||||
#include "TestUtils.h"
|
||||
#include "bayesnet/network/Network.h"
|
||||
#include "bayesnet/network/Node.h"
|
||||
#include "bayesnet/utils/bayesnetUtils.h"
|
||||
|
||||
void buildModel(bayesnet::Network& net, const std::vector<std::string>& features, const std::string& className)
|
||||
@@ -312,6 +313,15 @@ TEST_CASE("Test Bayesian Network", "[Network]")
|
||||
std::string invalid_feature = "Feature duck not found in Network::features";
|
||||
REQUIRE_THROWS_AS(net.fit(raw.Xv, raw.yv, raw.weightsv, features2, raw.className, raw.states), std::invalid_argument);
|
||||
REQUIRE_THROWS_WITH(net.fit(raw.Xv, raw.yv, raw.weightsv, features2, raw.className, raw.states), invalid_feature);
|
||||
// Add twice the same node name to the network => Nothing should happen
|
||||
net.addNode("A");
|
||||
net.addNode("A");
|
||||
// invalid state in checkfit
|
||||
auto net4 = bayesnet::Network();
|
||||
buildModel(net4, raw.features, raw.className);
|
||||
std::string invalid_state = "Feature sepallength not found in states";
|
||||
REQUIRE_THROWS_AS(net4.fit(raw.Xv, raw.yv, raw.weightsv, raw.features, raw.className, std::map<std::string, std::vector<int>>()), std::invalid_argument);
|
||||
REQUIRE_THROWS_WITH(net4.fit(raw.Xv, raw.yv, raw.weightsv, raw.features, raw.className, std::map<std::string, std::vector<int>>()), invalid_state);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,7 +7,9 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "TestUtils.h"
|
||||
#include "bayesnet/network/Network.h"
|
||||
|
||||
@@ -48,6 +50,73 @@ TEST_CASE("Test Node children and parents", "[Node]")
|
||||
REQUIRE(parents.size() == 0);
|
||||
REQUIRE(children.size() == 0);
|
||||
}
|
||||
TEST_CASE("Test Node computeCPT", "[Node]")
|
||||
{
|
||||
// Generate a test to test the computeCPT method of the Node class
|
||||
// Create a dataset with 3 features and 4 samples
|
||||
// The dataset is a 2D tensor with 4 rows and 4 columns
|
||||
auto dataset = torch::tensor({ {1, 0, 0, 1}, {1, 1, 2, 0}, {0, 1, 2, 1}, {0, 1, 0, 1} });
|
||||
auto states = std::vector<int>({ 2, 3, 3 });
|
||||
// Create a vector with the names of the features
|
||||
auto features = std::vector<std::string>{ "F1", "F2", "F3" };
|
||||
// Create a vector with the names of the classes
|
||||
auto className = std::string("Class");
|
||||
// weights
|
||||
auto weights = torch::tensor({ 1.0, 1.0, 1.0, 1.0 });
|
||||
std::vector<bayesnet::Node> nodes;
|
||||
for (int i = 0; i < features.size(); i++) {
|
||||
auto node = bayesnet::Node(features[i]);
|
||||
node.setNumStates(states[i]);
|
||||
nodes.push_back(node);
|
||||
}
|
||||
nodes.push_back(bayesnet::Node(className));
|
||||
nodes[features.size()].setNumStates(2);
|
||||
for (int i = 0; i < features.size(); i++) {
|
||||
// Add class node as parent of all feature nodes
|
||||
nodes[i].addParent(&nodes[features.size()]);
|
||||
// Node[0] -> Node[1], Node[2]
|
||||
if (i > 0)
|
||||
nodes[i].addParent(&nodes[0]);
|
||||
}
|
||||
features.push_back(className);
|
||||
// Compute the conditional probability table
|
||||
nodes[1].computeCPT(dataset, features, 0.0, weights);
|
||||
// Get the conditional probability table
|
||||
auto cpTable = nodes[1].getCPT();
|
||||
// Get the dimensions of the conditional probability table
|
||||
auto dimensions = cpTable.sizes();
|
||||
// Check the dimensions of the conditional probability table
|
||||
REQUIRE(dimensions.size() == 3);
|
||||
REQUIRE(dimensions[0] == 3);
|
||||
REQUIRE(dimensions[1] == 2);
|
||||
REQUIRE(dimensions[2] == 2);
|
||||
// Check the values of the conditional probability table
|
||||
REQUIRE(cpTable[0][0][0].item<float>() == Catch::Approx(0));
|
||||
REQUIRE(cpTable[0][0][1].item<float>() == Catch::Approx(0));
|
||||
REQUIRE(cpTable[0][1][0].item<float>() == Catch::Approx(0));
|
||||
REQUIRE(cpTable[0][1][1].item<float>() == Catch::Approx(1));
|
||||
REQUIRE(cpTable[1][0][0].item<float>() == Catch::Approx(0));
|
||||
REQUIRE(cpTable[1][0][1].item<float>() == Catch::Approx(1));
|
||||
REQUIRE(cpTable[1][1][0].item<float>() == Catch::Approx(1));
|
||||
REQUIRE(cpTable[1][1][1].item<float>() == Catch::Approx(0));
|
||||
// Compute evidence
|
||||
for (auto& node : nodes) {
|
||||
node.computeCPT(dataset, features, 0.0, weights);
|
||||
}
|
||||
auto evidence = std::map<std::string, int>{ { "F1", 0 }, { "F2", 1 }, { "F3", 1 } };
|
||||
REQUIRE(nodes[3].getFactorValue(evidence) == 0.5);
|
||||
// Oddities
|
||||
auto features_back = features;
|
||||
// Remove a parent from features
|
||||
features.pop_back();
|
||||
REQUIRE_THROWS_AS(nodes[0].computeCPT(dataset, features, 0.0, weights), std::logic_error);
|
||||
REQUIRE_THROWS_WITH(nodes[0].computeCPT(dataset, features, 0.0, weights), "Feature parent Class not found in dataset");
|
||||
// Remove a feature from features
|
||||
features = features_back;
|
||||
features.erase(features.begin());
|
||||
REQUIRE_THROWS_AS(nodes[0].computeCPT(dataset, features, 0.0, weights), std::logic_error);
|
||||
REQUIRE_THROWS_WITH(nodes[0].computeCPT(dataset, features, 0.0, weights), "Feature F1 not found in dataset");
|
||||
}
|
||||
TEST_CASE("TEST MinFill method", "[Node]")
|
||||
{
|
||||
// Generate a test to test the minFill method of the Node class
|
||||
|
@@ -14,14 +14,15 @@
|
||||
#include "bayesnet/feature_selection/IWSS.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
bayesnet::FeatureSelect* build_selector(RawDatasets& raw, std::string selector, double threshold)
|
||||
bayesnet::FeatureSelect* build_selector(RawDatasets& raw, std::string selector, double threshold, int max_features = 0)
|
||||
{
|
||||
max_features = max_features == 0 ? raw.features.size() : max_features;
|
||||
if (selector == "CFS") {
|
||||
return new bayesnet::CFS(raw.dataset, raw.features, raw.className, raw.features.size(), raw.classNumStates, raw.weights);
|
||||
return new bayesnet::CFS(raw.dataset, raw.features, raw.className, max_features, raw.classNumStates, raw.weights);
|
||||
} else if (selector == "FCBF") {
|
||||
return new bayesnet::FCBF(raw.dataset, raw.features, raw.className, raw.features.size(), raw.classNumStates, raw.weights, threshold);
|
||||
return new bayesnet::FCBF(raw.dataset, raw.features, raw.className, max_features, raw.classNumStates, raw.weights, threshold);
|
||||
} else if (selector == "IWSS") {
|
||||
return new bayesnet::IWSS(raw.dataset, raw.features, raw.className, raw.features.size(), raw.classNumStates, raw.weights, threshold);
|
||||
return new bayesnet::IWSS(raw.dataset, raw.features, raw.className, max_features, raw.classNumStates, raw.weights, threshold);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -94,4 +95,21 @@ TEST_CASE("Oddities", "[FeatureSelection]")
|
||||
REQUIRE_THROWS_WITH(selector->getFeatures(), message);
|
||||
REQUIRE_THROWS_WITH(selector->getScores(), message);
|
||||
delete selector;
|
||||
}
|
||||
TEST_CASE("Test threshold limits", "[FeatureSelection]")
|
||||
{
|
||||
auto raw = RawDatasets("diabetes", true);
|
||||
// FCBF Limits
|
||||
auto selector = build_selector(raw, "FCBF", 0.051);
|
||||
selector->fit();
|
||||
REQUIRE(selector->getFeatures().size() == 2);
|
||||
delete selector;
|
||||
selector = build_selector(raw, "FCBF", 1e-7, 3);
|
||||
selector->fit();
|
||||
REQUIRE(selector->getFeatures().size() == 3);
|
||||
delete selector;
|
||||
selector = build_selector(raw, "IWSS", 0.5, 5);
|
||||
selector->fit();
|
||||
REQUIRE(selector->getFeatures().size() == 5);
|
||||
delete selector;
|
||||
}
|
Reference in New Issue
Block a user