Loading src/loss_function/LossFunctionCalinskiHarabasz.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -23,9 +23,12 @@ LossFunctionCalinskiHarabasz::LossFunctionCalinskiHarabasz(const std::shared_ptr } double LossFunctionCalinskiHarabasz::test_loss(const std::vector<model_node_ptr>& feats) { init_mask("test"); return (*this)(feats); //get the centroids first if (_label_mask.size() == 0){ init_mask("train"); } populate_from_feats(feats); //now get the goods } Loading src/loss_function/LossFunctionClustering.hpp +1 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ protected: std::vector<int> _n_class_per_task; //!< Number of classes in the property int _n_class; //!< Number of classes in the property std::vector<double> _a; //!< matrix to copy values from the D_Matrix std::vector<double> _label_mask; //!< Label mask for prop train std::vector<double> _label_mask; //!< Label mask for prop train or test std::vector<double> _curr_centroid; //!< Stores the current calculated centroid; std::vector<double> _other_centroid; //!< Stores data for another centroid to calculate euclidian distance std::vector<double> _ones; //!< Ones vector for ddot copying Loading src/loss_function/LossFunctionDaviesBouldin.cpp +75 −1 Original line number Diff line number Diff line Loading @@ -34,10 +34,84 @@ double LossFunctionDaviesBouldin::operator()(const std::vector<model_node_ptr>& } double LossFunctionDaviesBouldin::test_loss(const std::vector<model_node_ptr>& feats) { if (_label_mask.size() == 0) { init_mask("train"); } populate_from_feats(feats); std::vector<std::vector<double>> centroids(_n_class, std::vector<double>(_n_feat, 0.0)); for (int cc = 0; cc < _n_class; ++cc) { const double* mask = &_label_mask[cc * _n_samp]; int n_points = std::accumulate(mask, mask + _n_samp, 0.0); if (n_points == 0) continue; int inc_mask = 1; for (int f = 0; f < _n_feat; ++f) { centroids[cc][f] = ddot_(&_n_samp, &_a[f], &_n_feat, mask, &inc_mask); centroids[cc][f] /= n_points; } } //overwrite labelmask with test after calculating all the centroids init_mask("test"); double dbi = 0.0; for (int key = 0; key < _n_class; key++) { int cluster_size = std::accumulate(_label_mask.begin() + key * _n_samp, _label_mask.begin() + (key + 1) * _n_samp, 0); if (cluster_size == 0) { continue; } double curr_spread = 0.0; for (int ii = 0; ii < _n_samp; ++ii) { if (_label_mask[key * _n_samp + ii] == 0) { continue; } curr_spread += std::sqrt(std::inner_product( centroids[key].begin(), centroids[key].end(), &_a[ii * _n_feat], 0.0, std::plus<>(), [](double a, double b){ return (a - b) * (a - b); } )); } curr_spread /= static_cast<double>(cluster_size); return (*this)(feats); double highest_ratio = 0.0; for (int other_key = 0; other_key < _n_class; other_key++) { if (other_key == key) { continue; } int n_other = std::accumulate(&_label_mask[other_key * _n_samp], &_label_mask[(other_key + 1) * _n_samp], 0); if (n_other == 0) { continue; } double dist = std::sqrt(std::inner_product( centroids[key].begin(), centroids[key].end(), centroids[other_key].begin(), 0.0, std::plus<>(), [](double a, double b){ return (a - b) * (a - b); } )); double other_spread = 0.0; for (int ii = 0; ii < _n_samp; ++ii) { if (_label_mask[other_key * _n_samp + ii] == 0) continue; other_spread += std::sqrt(std::inner_product( centroids[other_key].begin(), centroids[other_key].end(), &_a[ii * _n_feat], 0.0, std::plus<>(), [](double a, double b){ return (a - b) * (a - b); } )); } other_spread /= static_cast<double>(n_other); if (dist > 0.0) { double ratio = (curr_spread + other_spread) / dist; highest_ratio = std::max(highest_ratio, ratio); } } dbi += highest_ratio; } return dbi / static_cast<double>(_n_class); } double LossFunctionDaviesBouldin::get_dbi() { double worst_spread_avg = 0.0; Loading src/loss_function/LossFunctionSilhouetteScore.cpp +43 −5 Original line number Diff line number Diff line Loading @@ -13,9 +13,10 @@ LossFunctionSilhouetteScore::LossFunctionSilhouetteScore( bool fix_intercept, int n_feat) : LossFunctionClustering(prop_train, prop_test, task_sizes_train, std::move(task_sizes_test), fix_intercept, n_feat), _silhouette_scores(_n_samp, 0), _euclidean_distance(_n_samp * _n_samp, 0.0), _ai_bi(_n_class, 0.0), _silhouette_scores(_n_samp, 0) _ai_bi(_n_class, 0.0) { } Loading Loading @@ -45,13 +46,50 @@ double LossFunctionSilhouetteScore::operator()(const std::vector<model_node_ptr> } double LossFunctionSilhouetteScore::test_loss(const std::vector<model_node_ptr>& feats) { if (_label_mask.size() == 0) { init_mask("train"); } std::vector<double> train_mask = _label_mask; populate_from_feats(feats); //store the centroids from prop_train, that will be used with prop_test std::vector<std::vector<double>> centroids(_n_class, std::vector<double>(_n_feat, 0.0)); for (int cc = 0; cc < _n_class; ++cc) { const double* mask = &train_mask[cc * _n_samp]; int n_points = std::accumulate(mask, mask + _n_samp, 0.0); if (n_points == 0) continue; int inc_mask = 1; for (int f = 0; f < _n_feat; ++f) { centroids[cc][f] = ddot_(&_n_samp, &_a[f], &_n_feat, mask, &inc_mask); centroids[cc][f] /= n_points; } } //init mask for test now init_mask("test"); for (int s1 = 0; s1 < _n_samp; ++s1) { for (int cc = 0; cc < _n_class; ++cc) { _ai_bi[cc] = euclidean_distance(&_a[s1 * _n_feat], centroids[cc].data()); } int own_cluster = -1; for (int cc = 0; cc < _n_class; ++cc) { if (_label_mask[cc * _n_samp + s1] == 1) { own_cluster = cc; break; } } if (own_cluster == -1) { own_cluster = 0; } double ai = _ai_bi[own_cluster]; _ai_bi[own_cluster] = std::numeric_limits<double>::infinity(); double bi = *std::min_element(_ai_bi.begin(), _ai_bi.end()); _silhouette_scores[s1] = (bi - ai) / std::max(ai, bi); } return std::accumulate(_silhouette_scores.begin(), _silhouette_scores.end(), 0.0) / static_cast<double>(_silhouette_scores.size()); } return (*this)(feats); } double LossFunctionSilhouetteScore::euclidean_distance(const double* p1, const double* p2) { return std::sqrt(std::inner_product( p1, Loading tests/googletest/loss_function/test_davies_bouldin_loss.cc +5 −1 Original line number Diff line number Diff line Loading @@ -92,6 +92,7 @@ protected: std::fill_n(_prop_test.begin() + 5, 5, 1.0); std::fill_n(_prop_test.begin() + 10, 5, 2.0); std::fill_n(_prop_test.begin() + 15, 5, 3.0); } void TearDown() override { node_value_arrs::finalize_values_arr(); } Loading Loading @@ -173,7 +174,7 @@ TEST_F(LossFunctionDaviesBouldinTests, MultiClassTest) _model_phi.push_back(std::make_shared<ModelNode>(_phi[1])); _prop_train = {0,0,0, 1,1,1, 2,2,2, 3,3,3}; _prop_test = _prop_train; _prop_test = {0,1,0, 1,0,1, 2,3,2, 3,2,3}; LossFunctionDaviesBouldin loss( _prop_train, _prop_test, _task_sizes_train, _task_sizes_test, false, 2); Loading @@ -181,5 +182,8 @@ TEST_F(LossFunctionDaviesBouldinTests, MultiClassTest) loss(_model_phi); double dbi_feats_mulitclass = loss.get_dbi(); EXPECT_NEAR(dbi_feats_mulitclass, 0.06262969036057972, 0.0001); std::cout << "regular pipeline" << dbi_feats_mulitclass << std::endl; std::cout << "test_loss " << loss.test_loss(_model_phi) << std::endl; } } No newline at end of file Loading
src/loss_function/LossFunctionCalinskiHarabasz.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -23,9 +23,12 @@ LossFunctionCalinskiHarabasz::LossFunctionCalinskiHarabasz(const std::shared_ptr } double LossFunctionCalinskiHarabasz::test_loss(const std::vector<model_node_ptr>& feats) { init_mask("test"); return (*this)(feats); //get the centroids first if (_label_mask.size() == 0){ init_mask("train"); } populate_from_feats(feats); //now get the goods } Loading
src/loss_function/LossFunctionClustering.hpp +1 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ protected: std::vector<int> _n_class_per_task; //!< Number of classes in the property int _n_class; //!< Number of classes in the property std::vector<double> _a; //!< matrix to copy values from the D_Matrix std::vector<double> _label_mask; //!< Label mask for prop train std::vector<double> _label_mask; //!< Label mask for prop train or test std::vector<double> _curr_centroid; //!< Stores the current calculated centroid; std::vector<double> _other_centroid; //!< Stores data for another centroid to calculate euclidian distance std::vector<double> _ones; //!< Ones vector for ddot copying Loading
src/loss_function/LossFunctionDaviesBouldin.cpp +75 −1 Original line number Diff line number Diff line Loading @@ -34,10 +34,84 @@ double LossFunctionDaviesBouldin::operator()(const std::vector<model_node_ptr>& } double LossFunctionDaviesBouldin::test_loss(const std::vector<model_node_ptr>& feats) { if (_label_mask.size() == 0) { init_mask("train"); } populate_from_feats(feats); std::vector<std::vector<double>> centroids(_n_class, std::vector<double>(_n_feat, 0.0)); for (int cc = 0; cc < _n_class; ++cc) { const double* mask = &_label_mask[cc * _n_samp]; int n_points = std::accumulate(mask, mask + _n_samp, 0.0); if (n_points == 0) continue; int inc_mask = 1; for (int f = 0; f < _n_feat; ++f) { centroids[cc][f] = ddot_(&_n_samp, &_a[f], &_n_feat, mask, &inc_mask); centroids[cc][f] /= n_points; } } //overwrite labelmask with test after calculating all the centroids init_mask("test"); double dbi = 0.0; for (int key = 0; key < _n_class; key++) { int cluster_size = std::accumulate(_label_mask.begin() + key * _n_samp, _label_mask.begin() + (key + 1) * _n_samp, 0); if (cluster_size == 0) { continue; } double curr_spread = 0.0; for (int ii = 0; ii < _n_samp; ++ii) { if (_label_mask[key * _n_samp + ii] == 0) { continue; } curr_spread += std::sqrt(std::inner_product( centroids[key].begin(), centroids[key].end(), &_a[ii * _n_feat], 0.0, std::plus<>(), [](double a, double b){ return (a - b) * (a - b); } )); } curr_spread /= static_cast<double>(cluster_size); return (*this)(feats); double highest_ratio = 0.0; for (int other_key = 0; other_key < _n_class; other_key++) { if (other_key == key) { continue; } int n_other = std::accumulate(&_label_mask[other_key * _n_samp], &_label_mask[(other_key + 1) * _n_samp], 0); if (n_other == 0) { continue; } double dist = std::sqrt(std::inner_product( centroids[key].begin(), centroids[key].end(), centroids[other_key].begin(), 0.0, std::plus<>(), [](double a, double b){ return (a - b) * (a - b); } )); double other_spread = 0.0; for (int ii = 0; ii < _n_samp; ++ii) { if (_label_mask[other_key * _n_samp + ii] == 0) continue; other_spread += std::sqrt(std::inner_product( centroids[other_key].begin(), centroids[other_key].end(), &_a[ii * _n_feat], 0.0, std::plus<>(), [](double a, double b){ return (a - b) * (a - b); } )); } other_spread /= static_cast<double>(n_other); if (dist > 0.0) { double ratio = (curr_spread + other_spread) / dist; highest_ratio = std::max(highest_ratio, ratio); } } dbi += highest_ratio; } return dbi / static_cast<double>(_n_class); } double LossFunctionDaviesBouldin::get_dbi() { double worst_spread_avg = 0.0; Loading
src/loss_function/LossFunctionSilhouetteScore.cpp +43 −5 Original line number Diff line number Diff line Loading @@ -13,9 +13,10 @@ LossFunctionSilhouetteScore::LossFunctionSilhouetteScore( bool fix_intercept, int n_feat) : LossFunctionClustering(prop_train, prop_test, task_sizes_train, std::move(task_sizes_test), fix_intercept, n_feat), _silhouette_scores(_n_samp, 0), _euclidean_distance(_n_samp * _n_samp, 0.0), _ai_bi(_n_class, 0.0), _silhouette_scores(_n_samp, 0) _ai_bi(_n_class, 0.0) { } Loading Loading @@ -45,13 +46,50 @@ double LossFunctionSilhouetteScore::operator()(const std::vector<model_node_ptr> } double LossFunctionSilhouetteScore::test_loss(const std::vector<model_node_ptr>& feats) { if (_label_mask.size() == 0) { init_mask("train"); } std::vector<double> train_mask = _label_mask; populate_from_feats(feats); //store the centroids from prop_train, that will be used with prop_test std::vector<std::vector<double>> centroids(_n_class, std::vector<double>(_n_feat, 0.0)); for (int cc = 0; cc < _n_class; ++cc) { const double* mask = &train_mask[cc * _n_samp]; int n_points = std::accumulate(mask, mask + _n_samp, 0.0); if (n_points == 0) continue; int inc_mask = 1; for (int f = 0; f < _n_feat; ++f) { centroids[cc][f] = ddot_(&_n_samp, &_a[f], &_n_feat, mask, &inc_mask); centroids[cc][f] /= n_points; } } //init mask for test now init_mask("test"); for (int s1 = 0; s1 < _n_samp; ++s1) { for (int cc = 0; cc < _n_class; ++cc) { _ai_bi[cc] = euclidean_distance(&_a[s1 * _n_feat], centroids[cc].data()); } int own_cluster = -1; for (int cc = 0; cc < _n_class; ++cc) { if (_label_mask[cc * _n_samp + s1] == 1) { own_cluster = cc; break; } } if (own_cluster == -1) { own_cluster = 0; } double ai = _ai_bi[own_cluster]; _ai_bi[own_cluster] = std::numeric_limits<double>::infinity(); double bi = *std::min_element(_ai_bi.begin(), _ai_bi.end()); _silhouette_scores[s1] = (bi - ai) / std::max(ai, bi); } return std::accumulate(_silhouette_scores.begin(), _silhouette_scores.end(), 0.0) / static_cast<double>(_silhouette_scores.size()); } return (*this)(feats); } double LossFunctionSilhouetteScore::euclidean_distance(const double* p1, const double* p2) { return std::sqrt(std::inner_product( p1, Loading
tests/googletest/loss_function/test_davies_bouldin_loss.cc +5 −1 Original line number Diff line number Diff line Loading @@ -92,6 +92,7 @@ protected: std::fill_n(_prop_test.begin() + 5, 5, 1.0); std::fill_n(_prop_test.begin() + 10, 5, 2.0); std::fill_n(_prop_test.begin() + 15, 5, 3.0); } void TearDown() override { node_value_arrs::finalize_values_arr(); } Loading Loading @@ -173,7 +174,7 @@ TEST_F(LossFunctionDaviesBouldinTests, MultiClassTest) _model_phi.push_back(std::make_shared<ModelNode>(_phi[1])); _prop_train = {0,0,0, 1,1,1, 2,2,2, 3,3,3}; _prop_test = _prop_train; _prop_test = {0,1,0, 1,0,1, 2,3,2, 3,2,3}; LossFunctionDaviesBouldin loss( _prop_train, _prop_test, _task_sizes_train, _task_sizes_test, false, 2); Loading @@ -181,5 +182,8 @@ TEST_F(LossFunctionDaviesBouldinTests, MultiClassTest) loss(_model_phi); double dbi_feats_mulitclass = loss.get_dbi(); EXPECT_NEAR(dbi_feats_mulitclass, 0.06262969036057972, 0.0001); std::cout << "regular pipeline" << dbi_feats_mulitclass << std::endl; std::cout << "test_loss " << loss.test_loss(_model_phi) << std::endl; } } No newline at end of file