Vector<double> TestingAnalysis::calculate_binary_classification_tests(void) const { // Control sentence (if debug) #ifndef NDEBUG const MultilayerPerceptron* multilayer_perceptron_pointer = neural_network_pointer->get_multilayer_perceptron_pointer(); const unsigned inputs_number = multilayer_perceptron_pointer->get_inputs_number(); if(!data_set_pointer) { std::ostringstream buffer; buffer << "OpenNN Exception: TestingAnalysis class." << std::endl << "Vector<double> calculate_binary_classification_tests(void) const." << std::endl << "Data set is NULL." << std::endl; throw std::logic_error(buffer.str()); } const Variables& variables = data_set_pointer->get_variables(); const unsigned targets_number = variables.count_targets_number(); const unsigned outputs_number = multilayer_perceptron_pointer->get_outputs_number(); // Control sentence if(inputs_number != variables.count_inputs_number()) { std::ostringstream buffer; buffer << "OpenNN Exception: TestingAnalysis class." << std::endl << "Vector<double> calculate_binary_classification_tests(void) const." << std::endl << "Number of inputs in neural network is not equal to number of inputs in data set." << std::endl; throw std::logic_error(buffer.str()); } else if(outputs_number != 1) { std::ostringstream buffer; buffer << "OpenNN Exception: TestingAnalysis class." << std::endl << "Vector<double> calculate_binary_classification_tests(void) const." << std::endl << "Number of outputs in neural network must be one." << std::endl; throw std::logic_error(buffer.str()); } else if(targets_number != 1) { std::ostringstream buffer; buffer << "OpenNN Exception: TestingAnalysis class." << std::endl << "Vector<double> calculate_binary_classification_tests(void) const." << std::endl << "Number of targets in data set must be one." << std::endl; throw std::logic_error(buffer.str()); } #endif // Confusion matrix const Matrix<unsigned> confusion = calculate_confusion(); const unsigned true_positive = confusion[0][0]; const unsigned false_positive = confusion[0][1]; const unsigned false_negative = confusion[1][0]; const unsigned true_negative = confusion[1][1]; // Classification accuracy double classification_accuracy; if(true_positive + true_negative + false_positive + false_negative == 0) { classification_accuracy = 0.0; } else { classification_accuracy = (double)(true_positive + true_negative)/double(true_positive + true_negative + false_positive + false_negative); } // Error rate double error_rate; if(true_positive + true_negative + false_positive + false_negative == 0) { error_rate = 0.0; } else { error_rate = (double)(false_positive + false_negative)/(double)(true_positive + true_negative + false_positive + false_negative); } // Sensitivity double sensitivity; if(true_positive + false_negative == 0) { sensitivity = 0.0; } else { sensitivity = (double)true_positive/(double)(true_positive + false_negative); } // Specifity double specifity; if(true_negative + false_positive == 0) { specifity = 0.0; } else { specifity = (double)true_negative/(double)(true_negative + false_positive); } // Positive likelihood double positive_likelihood; if(classification_accuracy == 1.0) { positive_likelihood = 1.0; } else if(1.0 - specifity == 0.0) { positive_likelihood = 0.0; } else { positive_likelihood = sensitivity/(1.0 - specifity); } // Negative likelihood double negative_likelihood; if(classification_accuracy == 1.0) { negative_likelihood = 1.0; } else if(1.0 - sensitivity == 0.0) { negative_likelihood = 0.0; } else { negative_likelihood = specifity/(1.0 - sensitivity); } // Arrange vector Vector<double> binary_classification_test(6); binary_classification_test[0] = classification_accuracy; binary_classification_test[1] = error_rate; binary_classification_test[2] = sensitivity; binary_classification_test[3] = specifity; binary_classification_test[4] = positive_likelihood; binary_classification_test[5] = negative_likelihood; return(binary_classification_test); }
KappaCoefficientOptimizationThreshold::KappaCoefficientOptimizationThresholdResults* KappaCoefficientOptimizationThreshold::perform_threshold_selection(void) { #ifdef __OPENNN_DEBUG__ check(); #endif KappaCoefficientOptimizationThresholdResults* results = new KappaCoefficientOptimizationThresholdResults(); const LossIndex* loss_index_pointer = training_strategy_pointer->get_loss_index_pointer(); NeuralNetwork* neural_network_pointer = loss_index_pointer->get_neural_network_pointer(); double current_threshold = minimum_threshold; Matrix<size_t> current_confusion; Vector<double> current_binary_classification_test; double current_kappa_coefficient; double po, pe, prA, prB; const size_t instances_number = loss_index_pointer->get_data_set_pointer()->get_instances_pointer()->count_selection_instances_number(); double optimum_threshold; Vector<double> optimal_binary_classification_test(15,1); double optimum_kappa_coefficient = 0.0; size_t iterations = 0; bool end = false; while (!end) { current_confusion = calculate_confusion(current_threshold); current_binary_classification_test = calculate_binary_classification_test(current_confusion); po = (current_confusion(0,0) + current_confusion(1,1))/(double)instances_number; prA = (current_confusion(0,0) + current_confusion(0,1))/(double)instances_number; prB = (current_confusion(0,0) + current_confusion(1,0))/(double)instances_number; pe = prA*prB + (1-prA)*(1-prB); current_kappa_coefficient = (po-pe)/(1-pe); results->threshold_data.push_back(current_threshold); if(reserve_binary_classification_tests_data) { results->binary_classification_test_data.push_back(current_binary_classification_test); } if(reserve_function_data) { results->function_data.push_back(current_kappa_coefficient); } if (current_kappa_coefficient > optimum_kappa_coefficient || (current_kappa_coefficient == optimum_kappa_coefficient && current_binary_classification_test[1] < optimal_binary_classification_test[1])) { optimum_kappa_coefficient = current_kappa_coefficient; optimum_threshold = current_threshold; optimal_binary_classification_test.set(current_binary_classification_test); } iterations++; if (current_confusion(0,1) == 0 && current_confusion(1,0) == 0) { end = true; if(display) { std::cout << "Perfect confusion matrix reached." << std::endl; } results->stopping_condition = ThresholdSelectionAlgorithm::PerfectConfusionMatrix; } else if (current_threshold == maximum_threshold) { end = true; if(display) { std::cout << "Algorithm finished." << std::endl; } results->stopping_condition = ThresholdSelectionAlgorithm::AlgorithmFinished; } if (display) { std::cout << "Iteration: " << iterations << std::endl; std::cout << "Current threshold: " << current_threshold << std::endl; std::cout << "Current error: " << current_binary_classification_test[1] << std::endl; std::cout << "Current sensitivity: " << current_binary_classification_test[2] << std::endl; std::cout << "Current specifity: " << current_binary_classification_test[3] << std::endl; std::cout << "Current Kappa coefficient: " << current_kappa_coefficient << std::endl; std::cout << "Confusion matrix: " << std::endl << current_confusion << std::endl; std::cout << std::endl; } current_threshold = fmin(maximum_threshold, current_threshold + step); } if (display) { std::cout << "Optimum threshold: " << optimum_threshold << std::endl; std::cout << "Optimal error: " << optimal_binary_classification_test[1] << std::endl; } results->iterations_number = iterations; results->final_threshold = optimum_threshold; results->final_function_value = optimum_kappa_coefficient; neural_network_pointer->get_probabilistic_layer_pointer()->set_decision_threshold(optimum_threshold); return(results); }