From 7b20eb1231e4ced1175ba027bc218fb31d3db411 Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Fri, 13 Mar 2020 17:46:31 +0530 Subject: [PATCH 1/9] Add shuffle data paramter to data_split --- src/mlpack/core/data/split_data.hpp | 40 +++++++++++++------ .../preprocess/preprocess_split_main.cpp | 13 +++++- .../main_tests/preprocess_split_test.cpp | 31 ++++++++++++++ src/mlpack/tests/split_data_test.cpp | 17 +++++++- 4 files changed, 86 insertions(+), 15 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 28b0bcf966..0f0ac3a541 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -44,6 +44,7 @@ namespace data { * @param trainLabel Vector to store training labels into. * @param testLabel Vector to store test labels into. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). + * @param shuffleData True(Default) if you want to shuffle data. */ template void Split(const arma::Mat& input, @@ -52,7 +53,8 @@ void Split(const arma::Mat& input, arma::Mat& testData, arma::Row& trainLabel, arma::Row& testLabel, - const double testRatio) + const double testRatio, + bool shuffleData = true) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; @@ -61,9 +63,13 @@ void Split(const arma::Mat& input, trainLabel.set_size(trainSize); testLabel.set_size(testSize); - const arma::Col order = - arma::shuffle(arma::linspace>(0, input.n_cols - 1, - input.n_cols)); + arma::Col order; + if (shuffleData) + order = arma::shuffle(arma::linspace>(0, + input.n_cols - 1, input.n_cols)); + else + order = arma::linspace>(0, input.n_cols - 1, + input.n_cols); for (size_t i = 0; i != trainSize; ++i) { @@ -98,21 +104,27 @@ void Split(const arma::Mat& input, * @param trainData Matrix to store training data into. * @param testData Matrix to store test data into. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). + * @param shuffleData True(Default) if you want to shuffle data. */ template void Split(const arma::Mat& input, arma::Mat& trainData, arma::Mat& testData, - const double testRatio) + const double testRatio, + bool shuffleData = true) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; trainData.set_size(input.n_rows, trainSize); testData.set_size(input.n_rows, testSize); - const arma::Col order = - arma::shuffle(arma::linspace>(0, input.n_cols -1, - input.n_cols)); + arma::Col order; + if (shuffleData) + order = arma::shuffle(arma::linspace>(0, + input.n_cols -1, input.n_cols)); + else + order = arma::linspace>(0, input.n_cols -1, + input.n_cols); for (size_t i = 0; i != trainSize; ++i) { @@ -140,6 +152,7 @@ void Split(const arma::Mat& input, * @param input Input dataset to split. * @param label Input labels to split. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). + * @param shuffleData True(Default) if you want to shuffle data. * @return std::tuple containing trainData (arma::Mat), testData * (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row). */ @@ -147,7 +160,8 @@ template std::tuple, arma::Mat, arma::Row, arma::Row> Split(const arma::Mat& input, const arma::Row& inputLabel, - const double testRatio) + const double testRatio, + bool shuffleData = true) { arma::Mat trainData; arma::Mat testData; @@ -155,7 +169,7 @@ Split(const arma::Mat& input, arma::Row testLabel; Split(input, inputLabel, trainData, testData, trainLabel, testLabel, - testRatio); + testRatio, shuffleData); return std::make_tuple(std::move(trainData), std::move(testData), @@ -176,17 +190,19 @@ Split(const arma::Mat& input, * * @param input Input dataset to split. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). + * @param shuffleData True(Default) if you want to shuffle data. * @return std::tuple containing trainData (arma::Mat) * and testData (arma::Mat). */ template std::tuple, arma::Mat> Split(const arma::Mat& input, - const double testRatio) + const double testRatio, + bool shuffleData = true) { arma::Mat trainData; arma::Mat testData; - Split(input, trainData, testData, testRatio); + Split(input, trainData, testData, testRatio, shuffleData); return std::make_tuple(std::move(trainData), std::move(testData)); diff --git a/src/mlpack/methods/preprocess/preprocess_split_main.cpp b/src/mlpack/methods/preprocess/preprocess_split_main.cpp index 3de7745d31..ab592620c6 100644 --- a/src/mlpack/methods/preprocess/preprocess_split_main.cpp +++ b/src/mlpack/methods/preprocess/preprocess_split_main.cpp @@ -45,6 +45,13 @@ PROGRAM_INFO("Split Data", PRINT_CALL("preprocess_split", "input", "X", "training", "X_train", "test", "X_test", "test_ratio", 0.4) + "\n\n" + "Also by default the dataset is shuffled and splited, you can provide " + + PRINT_PARAM_STRING("shuffle_data") +" to avoid shuffling of the data, " + + "an example to avoid shuffling of data is as" + "\n\n" + + PRINT_CALL("preprocess_split", "input", "X", "training", "X_train", "test", + "X_test", "test_ratio", 0.4 , "shuffle_data", true) + + "\n\n" "If we had a dataset " + PRINT_DATASET("X") + " and associated labels " + PRINT_DATASET("y") + ", and we wanted to split these into " + PRINT_DATASET("X_train") + ", " + PRINT_DATASET("y_train") + ", " + @@ -73,6 +80,7 @@ PARAM_DOUBLE_IN("test_ratio", "Ratio of test set; if not set," "the ratio defaults to 0.2", "r", 0.2); PARAM_INT_IN("seed", "Random seed (0 for std::time(NULL)).", "s", 0); +PARAM_FLAG("shuffle_data", "Avoid shuffling and spliting the data.", "S"); using namespace mlpack; using namespace mlpack::util; @@ -83,6 +91,7 @@ static void mlpackMain() { // Parse command line options. const double testRatio = CLI::GetParam("test_ratio"); + const bool shuffleData = CLI::GetParam("shuffle_data"); if (CLI::GetParam("seed") == 0) mlpack::math::RandomSeed(std::time(NULL)); @@ -129,7 +138,7 @@ static void mlpackMain() CLI::GetParam>("input_labels"); arma::Row labelsRow = labels.row(0); - const auto value = data::Split(data, labelsRow, testRatio); + const auto value = data::Split(data, labelsRow, testRatio, !shuffleData); Log::Info << "Training data contains " << get<0>(value).n_cols << " points." << endl; Log::Info << "Test data contains " << get<1>(value).n_cols << " points." @@ -148,7 +157,7 @@ static void mlpackMain() } else // We have no labels, so just split the dataset. { - const auto value = data::Split(data, testRatio); + const auto value = data::Split(data, testRatio, !shuffleData); Log::Info << "Training data contains " << get<0>(value).n_cols << " points." << endl; Log::Info << "Test data contains " << get<1>(value).n_cols << " points." diff --git a/src/mlpack/tests/main_tests/preprocess_split_test.cpp b/src/mlpack/tests/main_tests/preprocess_split_test.cpp index 509a74a3d3..0f42d3e329 100644 --- a/src/mlpack/tests/main_tests/preprocess_split_test.cpp +++ b/src/mlpack/tests/main_tests/preprocess_split_test.cpp @@ -199,4 +199,35 @@ BOOST_AUTO_TEST_CASE(PreprocessSplitUnityTestRatioTest) labelSize); } +/** + * Check shuffle_data flag is working as expected. + */ +BOOST_AUTO_TEST_CASE(PreprocessSplitLabelSuffleDataTest) +{ + // Load custom dataset. + arma::mat inputData; + data::Load("vc2.csv", inputData); + + // Store size of input dataset. + int inputSize = inputData.n_cols; + + // Input custom data points and labels. + SetInputParam("input", inputData); + + // Input test_ratio. + SetInputParam("test_ratio", (double) 0.1); + SetInputParam("shuffle_data", true); + mlpackMain(); + + // Now check that the output has desired dimensions. + BOOST_REQUIRE_EQUAL(CLI::GetParam("training").n_cols, + std::ceil(0.9 * inputSize)); + BOOST_REQUIRE_EQUAL(CLI::GetParam("test").n_cols, + std::floor(0.1 * inputSize)); + + arma::mat concat = arma::join_rows(CLI::GetParam("training"), + CLI::GetParam("test")); + CheckMatrices(inputData, concat); +} + BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 2846307b29..3f41c1e0eb 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -94,7 +94,7 @@ void CheckDuplication(const Row& trainLabels, BOOST_REQUIRE_EQUAL(counts[i], 1); } -BOOST_AUTO_TEST_CASE(SplitDataResultMat) +BOOST_AUTO_TEST_CASE(SplitShuffleDataResultMat) { mat input(2, 10); size_t count = 0; // count for putting unique sequential values @@ -108,6 +108,21 @@ BOOST_AUTO_TEST_CASE(SplitDataResultMat) CheckMatEqual(input, concat); } +BOOST_AUTO_TEST_CASE(SplitDataResultMat) +{ + mat input(2, 10); + size_t count = 0; // count for putting unique sequential values + input.imbue([&count] () { return ++count; }); + + const auto value = Split(input, 0.2, false); + BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // train data + BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // test data + + mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); + // Order matters here. + CheckMatrices(input, concat); +} + BOOST_AUTO_TEST_CASE(SplitLabeledDataResultMat) { mat input(2, 10); From 96cb12e41dc3b0269195bc5bbf7f5fc808d572ed Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Wed, 18 Mar 2020 16:09:48 +0530 Subject: [PATCH 2/9] Improve Docs and styling --- src/mlpack/core/data/split_data.hpp | 20 ++++++++++++++++---- src/mlpack/tests/split_data_test.cpp | 12 ++++++------ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 0f0ac3a541..cc0f0349e1 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -44,7 +44,8 @@ namespace data { * @param trainLabel Vector to store training labels into. * @param testLabel Vector to store test labels into. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). - * @param shuffleData True(Default) if you want to shuffle data. + * @param shuffleData If true, the sample order is shuffled; otherwise, each + * sample is visited in linear order. (Default true). */ template void Split(const arma::Mat& input, @@ -65,11 +66,15 @@ void Split(const arma::Mat& input, arma::Col order; if (shuffleData) + { order = arma::shuffle(arma::linspace>(0, input.n_cols - 1, input.n_cols)); + } else + { order = arma::linspace>(0, input.n_cols - 1, input.n_cols); + } for (size_t i = 0; i != trainSize; ++i) { @@ -104,7 +109,8 @@ void Split(const arma::Mat& input, * @param trainData Matrix to store training data into. * @param testData Matrix to store test data into. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). - * @param shuffleData True(Default) if you want to shuffle data. + * @param shuffleData If true, the sample order is shuffled; otherwise, each + * sample is visited in linear order. (Default true). */ template void Split(const arma::Mat& input, @@ -120,11 +126,15 @@ void Split(const arma::Mat& input, arma::Col order; if (shuffleData) + { order = arma::shuffle(arma::linspace>(0, input.n_cols -1, input.n_cols)); + } else + { order = arma::linspace>(0, input.n_cols -1, input.n_cols); + } for (size_t i = 0; i != trainSize; ++i) { @@ -152,7 +162,8 @@ void Split(const arma::Mat& input, * @param input Input dataset to split. * @param label Input labels to split. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). - * @param shuffleData True(Default) if you want to shuffle data. + * @param shuffleData If true, the sample order is shuffled; otherwise, each + * sample is visited in linear order. (Default true). * @return std::tuple containing trainData (arma::Mat), testData * (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row). */ @@ -190,7 +201,8 @@ Split(const arma::Mat& input, * * @param input Input dataset to split. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). - * @param shuffleData True(Default) if you want to shuffle data. + * @param shuffleData If true, the sample order is shuffled; otherwise, each + * sample is visited in linear order. (Default true). * @return std::tuple containing trainData (arma::Mat) * and testData (arma::Mat). */ diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 3f41c1e0eb..27b281b889 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -97,12 +97,12 @@ void CheckDuplication(const Row& trainLabels, BOOST_AUTO_TEST_CASE(SplitShuffleDataResultMat) { mat input(2, 10); - size_t count = 0; // count for putting unique sequential values + size_t count = 0; // counter for unique sequential values input.imbue([&count] () { return ++count; }); const auto value = Split(input, 0.2); - BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // train data - BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // test data + BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // Train data + BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // Test data mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); CheckMatEqual(input, concat); @@ -111,12 +111,12 @@ BOOST_AUTO_TEST_CASE(SplitShuffleDataResultMat) BOOST_AUTO_TEST_CASE(SplitDataResultMat) { mat input(2, 10); - size_t count = 0; // count for putting unique sequential values + size_t count = 0; // counter for unique sequential values input.imbue([&count] () { return ++count; }); const auto value = Split(input, 0.2, false); - BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // train data - BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // test data + BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // Train data + BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // Test data mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); // Order matters here. From bdc6e98ec1a0455dfba2054484a2778e138fe74a Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Thu, 19 Mar 2020 21:02:06 +0530 Subject: [PATCH 3/9] pendatic style issues :) --- src/mlpack/tests/split_data_test.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 27b281b889..d8adf14c0a 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -97,12 +97,12 @@ void CheckDuplication(const Row& trainLabels, BOOST_AUTO_TEST_CASE(SplitShuffleDataResultMat) { mat input(2, 10); - size_t count = 0; // counter for unique sequential values + size_t count = 0; // Counter for unique sequential values. input.imbue([&count] () { return ++count; }); const auto value = Split(input, 0.2); - BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // Train data - BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // Test data + BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // Train data. + BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // Test data. mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); CheckMatEqual(input, concat); @@ -111,12 +111,12 @@ BOOST_AUTO_TEST_CASE(SplitShuffleDataResultMat) BOOST_AUTO_TEST_CASE(SplitDataResultMat) { mat input(2, 10); - size_t count = 0; // counter for unique sequential values + size_t count = 0; // Counter for unique sequential values. input.imbue([&count] () { return ++count; }); const auto value = Split(input, 0.2, false); - BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // Train data - BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // Test data + BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 8); // Train data. + BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 2); // Test data. mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); // Order matters here. From c572431808d73226fbfd30b64579b7c1e785bedb Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Mon, 30 Mar 2020 23:01:25 +0530 Subject: [PATCH 4/9] Change implemenation of split_data for shuffle=false --- HISTORY.md | 2 + src/mlpack/core/data/split_data.hpp | 53 +++++++++---------- .../preprocess/preprocess_split_main.cpp | 2 +- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index c401f0fc68..b149dfd270 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -60,6 +60,8 @@ * Add Hinge Embedding Loss Function (#2229). + * Add parameter to avoid shuffling of data in preprocess_split (#2293). + ### mlpack 3.2.2 ###### 2019-11-26 * Add `valid` and `same` padding option in `Convolution` and `Atrous diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index cc0f0349e1..76841728be 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -64,28 +64,28 @@ void Split(const arma::Mat& input, trainLabel.set_size(trainSize); testLabel.set_size(testSize); - arma::Col order; if (shuffleData) { + arma::Col order; order = arma::shuffle(arma::linspace>(0, input.n_cols - 1, input.n_cols)); + for (size_t i = 0; i != trainSize; ++i) + { + trainData.col(i) = input.col(order[i]); + trainLabel(i) = inputLabel(order[i]); + } + for (size_t i = 0; i != testSize; ++i) + { + testData.col(i) = input.col(order[i + trainSize]); + testLabel(i) = inputLabel(order[i + trainSize]); + } } else { - order = arma::linspace>(0, input.n_cols - 1, - input.n_cols); - } - - for (size_t i = 0; i != trainSize; ++i) - { - trainData.col(i) = input.col(order[i]); - trainLabel(i) = inputLabel(order[i]); - } - - for (size_t i = 0; i != testSize; ++i) - { - testData.col(i) = input.col(order[i + trainSize]); - testLabel(i) = inputLabel(order[i + trainSize]); + trainData = input.cols(0, trainSize - 1); + testData = input.cols(trainSize , input.n_cols - 1); + trainLabel = inputLabel.subvec(0, trainSize - 1); + testLabel = inputLabel.subvec(trainSize , input.n_cols - 1); } } @@ -124,25 +124,24 @@ void Split(const arma::Mat& input, trainData.set_size(input.n_rows, trainSize); testData.set_size(input.n_rows, testSize); - arma::Col order; if (shuffleData) { + arma::Col order; order = arma::shuffle(arma::linspace>(0, input.n_cols -1, input.n_cols)); + for (size_t i = 0; i != trainSize; ++i) + { + trainData.col(i) = input.col(order[i]); + } + for (size_t i = 0; i != testSize; ++i) + { + testData.col(i) = input.col(order[i + trainSize]); + } } else { - order = arma::linspace>(0, input.n_cols -1, - input.n_cols); - } - - for (size_t i = 0; i != trainSize; ++i) - { - trainData.col(i) = input.col(order[i]); - } - for (size_t i = 0; i != testSize; ++i) - { - testData.col(i) = input.col(order[i + trainSize]); + trainData = input.cols(0, trainSize - 1); + testData = input.cols(trainSize , input.n_cols - 1); } } diff --git a/src/mlpack/methods/preprocess/preprocess_split_main.cpp b/src/mlpack/methods/preprocess/preprocess_split_main.cpp index ab592620c6..8c13a2650b 100644 --- a/src/mlpack/methods/preprocess/preprocess_split_main.cpp +++ b/src/mlpack/methods/preprocess/preprocess_split_main.cpp @@ -80,7 +80,7 @@ PARAM_DOUBLE_IN("test_ratio", "Ratio of test set; if not set," "the ratio defaults to 0.2", "r", 0.2); PARAM_INT_IN("seed", "Random seed (0 for std::time(NULL)).", "s", 0); -PARAM_FLAG("shuffle_data", "Avoid shuffling and spliting the data.", "S"); +PARAM_FLAG("shuffle_data", "Avoid shuffling and splitting the data.", "S"); using namespace mlpack; using namespace mlpack::util; From 93e1209e0e9ed5b99b1fe50dbe2cb7d11a88bfdd Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Thu, 23 Apr 2020 13:37:26 +0530 Subject: [PATCH 5/9] Use subvec instead of for loops --- src/mlpack/core/data/split_data.hpp | 44 +++++++------------ .../preprocess/preprocess_split_main.cpp | 8 ++-- .../main_tests/preprocess_split_test.cpp | 4 +- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 76841728be..efa817f6fb 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -45,7 +45,7 @@ namespace data { * @param testLabel Vector to store test labels into. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). * @param shuffleData If true, the sample order is shuffled; otherwise, each - * sample is visited in linear order. (Default true). + * sample is visited in linear order. (Default true.) */ template void Split(const arma::Mat& input, @@ -55,7 +55,7 @@ void Split(const arma::Mat& input, arma::Row& trainLabel, arma::Row& testLabel, const double testRatio, - bool shuffleData = true) + const bool shuffleData = true) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; @@ -66,19 +66,12 @@ void Split(const arma::Mat& input, if (shuffleData) { - arma::Col order; - order = arma::shuffle(arma::linspace>(0, - input.n_cols - 1, input.n_cols)); - for (size_t i = 0; i != trainSize; ++i) - { - trainData.col(i) = input.col(order[i]); - trainLabel(i) = inputLabel(order[i]); - } - for (size_t i = 0; i != testSize; ++i) - { - testData.col(i) = input.col(order[i + trainSize]); - testLabel(i) = inputLabel(order[i + trainSize]); - } + arma::uvec order = arma::shuffle(arma::linspace( + 0, input.n_cols - 1, input.n_cols)); + trainData = input.cols(order.subvec(0, trainSize - 1)); + trainLabel = inputLabel.cols(order.subvec(0, trainSize - 1)); + testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); + testLabel = inputLabel.cols(order.subvec(trainSize, input.n_cols - 1)); } else { @@ -117,7 +110,7 @@ void Split(const arma::Mat& input, arma::Mat& trainData, arma::Mat& testData, const double testRatio, - bool shuffleData = true) + const bool shuffleData = true) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; @@ -126,17 +119,10 @@ void Split(const arma::Mat& input, if (shuffleData) { - arma::Col order; - order = arma::shuffle(arma::linspace>(0, - input.n_cols -1, input.n_cols)); - for (size_t i = 0; i != trainSize; ++i) - { - trainData.col(i) = input.col(order[i]); - } - for (size_t i = 0; i != testSize; ++i) - { - testData.col(i) = input.col(order[i + trainSize]); - } + arma::uvec order = arma::shuffle(arma::linspace( + 0, input.n_cols - 1, input.n_cols)); + trainData = input.cols(order.subvec(0, trainSize - 1)); + testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); } else { @@ -171,7 +157,7 @@ std::tuple, arma::Mat, arma::Row, arma::Row> Split(const arma::Mat& input, const arma::Row& inputLabel, const double testRatio, - bool shuffleData = true) + const bool shuffleData = true) { arma::Mat trainData; arma::Mat testData; @@ -209,7 +195,7 @@ template std::tuple, arma::Mat> Split(const arma::Mat& input, const double testRatio, - bool shuffleData = true) + const bool shuffleData = true) { arma::Mat trainData; arma::Mat testData; diff --git a/src/mlpack/methods/preprocess/preprocess_split_main.cpp b/src/mlpack/methods/preprocess/preprocess_split_main.cpp index 8c13a2650b..b975ab6ea6 100644 --- a/src/mlpack/methods/preprocess/preprocess_split_main.cpp +++ b/src/mlpack/methods/preprocess/preprocess_split_main.cpp @@ -46,11 +46,11 @@ PROGRAM_INFO("Split Data", "X_test", "test_ratio", 0.4) + "\n\n" "Also by default the dataset is shuffled and splited, you can provide " + - PRINT_PARAM_STRING("shuffle_data") +" to avoid shuffling of the data, " + + PRINT_PARAM_STRING("no_shuffle") +" to avoid shuffling of the data, " + "an example to avoid shuffling of data is as" "\n\n" + PRINT_CALL("preprocess_split", "input", "X", "training", "X_train", "test", - "X_test", "test_ratio", 0.4 , "shuffle_data", true) + + "X_test", "test_ratio", 0.4 , "no_shuffle", true) + "\n\n" "If we had a dataset " + PRINT_DATASET("X") + " and associated labels " + PRINT_DATASET("y") + ", and we wanted to split these into " + @@ -80,7 +80,7 @@ PARAM_DOUBLE_IN("test_ratio", "Ratio of test set; if not set," "the ratio defaults to 0.2", "r", 0.2); PARAM_INT_IN("seed", "Random seed (0 for std::time(NULL)).", "s", 0); -PARAM_FLAG("shuffle_data", "Avoid shuffling and splitting the data.", "S"); +PARAM_FLAG("no_shuffle", "Avoid shuffling and splitting the data.", "S"); using namespace mlpack; using namespace mlpack::util; @@ -91,7 +91,7 @@ static void mlpackMain() { // Parse command line options. const double testRatio = CLI::GetParam("test_ratio"); - const bool shuffleData = CLI::GetParam("shuffle_data"); + const bool shuffleData = CLI::GetParam("no_shuffle"); if (CLI::GetParam("seed") == 0) mlpack::math::RandomSeed(std::time(NULL)); diff --git a/src/mlpack/tests/main_tests/preprocess_split_test.cpp b/src/mlpack/tests/main_tests/preprocess_split_test.cpp index 0f42d3e329..34d1515f0a 100644 --- a/src/mlpack/tests/main_tests/preprocess_split_test.cpp +++ b/src/mlpack/tests/main_tests/preprocess_split_test.cpp @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(PreprocessSplitUnityTestRatioTest) /** * Check shuffle_data flag is working as expected. */ -BOOST_AUTO_TEST_CASE(PreprocessSplitLabelSuffleDataTest) +BOOST_AUTO_TEST_CASE(PreprocessSplitLabelShuffleDataTest) { // Load custom dataset. arma::mat inputData; @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(PreprocessSplitLabelSuffleDataTest) // Input test_ratio. SetInputParam("test_ratio", (double) 0.1); - SetInputParam("shuffle_data", true); + SetInputParam("no_shuffle", true); mlpackMain(); // Now check that the output has desired dimensions. From b5fe50e4cb6dfaacb9129acd4718cc185426fe95 Mon Sep 17 00:00:00 2001 From: jeffin sam Date: Thu, 23 Apr 2020 13:43:23 +0530 Subject: [PATCH 6/9] Update HISTORY.md Co-Authored-By: Marcus Edel --- HISTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 11bc2fb620..e7714b124a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -91,7 +91,7 @@ * Add Soft Shrink Activation Function (#2174). * Add Hinge Embedding Loss Function (#2229). - + * Add Cosine Embedding Loss Function (#2209). * Add Margin Ranking Loss Function (#2264). From 43e1e27a1c7e5f3fe18c4d57090bbba0bdcceed2 Mon Sep 17 00:00:00 2001 From: jeffin sam Date: Mon, 4 May 2020 00:42:58 +0530 Subject: [PATCH 7/9] Apply suggestions from code review Co-authored-by: Ryan Curtin --- HISTORY.md | 1 - src/mlpack/methods/preprocess/preprocess_split_main.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index e7714b124a..95fd15edb9 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -91,7 +91,6 @@ * Add Soft Shrink Activation Function (#2174). * Add Hinge Embedding Loss Function (#2229). - * Add Cosine Embedding Loss Function (#2209). * Add Margin Ranking Loss Function (#2264). diff --git a/src/mlpack/methods/preprocess/preprocess_split_main.cpp b/src/mlpack/methods/preprocess/preprocess_split_main.cpp index b975ab6ea6..ccedb11b43 100644 --- a/src/mlpack/methods/preprocess/preprocess_split_main.cpp +++ b/src/mlpack/methods/preprocess/preprocess_split_main.cpp @@ -45,12 +45,12 @@ PROGRAM_INFO("Split Data", PRINT_CALL("preprocess_split", "input", "X", "training", "X_train", "test", "X_test", "test_ratio", 0.4) + "\n\n" - "Also by default the dataset is shuffled and splited, you can provide " + - PRINT_PARAM_STRING("no_shuffle") +" to avoid shuffling of the data, " + - "an example to avoid shuffling of data is as" + "Also by default the dataset is shuffled and split; you can provide the " + + PRINT_PARAM_STRING("no_shuffle") + " option to avoid shuffling the " + "data; an example to avoid shuffling of data is:" "\n\n" + PRINT_CALL("preprocess_split", "input", "X", "training", "X_train", "test", - "X_test", "test_ratio", 0.4 , "no_shuffle", true) + + "X_test", "test_ratio", 0.4, "no_shuffle", true) + "\n\n" "If we had a dataset " + PRINT_DATASET("X") + " and associated labels " + PRINT_DATASET("y") + ", and we wanted to split these into " + From c0253045c62aa8ce8096d334a38c338f31e5a8a7 Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Mon, 4 May 2020 00:53:27 +0530 Subject: [PATCH 8/9] handle edge case --- src/mlpack/core/data/split_data.hpp | 41 ++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index efa817f6fb..aedb2ad3b4 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -68,17 +68,29 @@ void Split(const arma::Mat& input, { arma::uvec order = arma::shuffle(arma::linspace( 0, input.n_cols - 1, input.n_cols)); - trainData = input.cols(order.subvec(0, trainSize - 1)); - trainLabel = inputLabel.cols(order.subvec(0, trainSize - 1)); + if (trainSize > 0) + { + trainData = input.cols(order.subvec(0, trainSize - 1)); + trainLabel = inputLabel.cols(order.subvec(0, trainSize - 1)); + } + if (trainSize < input.n_cols) + { testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); testLabel = inputLabel.cols(order.subvec(trainSize, input.n_cols - 1)); + } } else { - trainData = input.cols(0, trainSize - 1); - testData = input.cols(trainSize , input.n_cols - 1); - trainLabel = inputLabel.subvec(0, trainSize - 1); - testLabel = inputLabel.subvec(trainSize , input.n_cols - 1); + if (trainSize > 0) + { + trainData = input.cols(0, trainSize - 1); + trainLabel = inputLabel.subvec(0, trainSize - 1); + } + if (trainSize < input.n_cols) + { + testData = input.cols(trainSize , input.n_cols - 1); + testLabel = inputLabel.subvec(trainSize , input.n_cols - 1); + } } } @@ -121,13 +133,22 @@ void Split(const arma::Mat& input, { arma::uvec order = arma::shuffle(arma::linspace( 0, input.n_cols - 1, input.n_cols)); - trainData = input.cols(order.subvec(0, trainSize - 1)); - testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); + + if (trainSize > 0) + trainData = input.cols(order.subvec(0, trainSize - 1)); + + if (trainSize < input.n_cols) + testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); + } else { - trainData = input.cols(0, trainSize - 1); - testData = input.cols(trainSize , input.n_cols - 1); + + if (trainSize > 0) + trainData = input.cols(0, trainSize - 1); + + if (trainSize < input.n_cols) + testData = input.cols(trainSize , input.n_cols - 1); } } From 58ec7b87d37818121a68cdc707bedfb3a10ae0e5 Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Mon, 4 May 2020 01:52:30 +0530 Subject: [PATCH 9/9] Style correction and add test for 0 and 1 ration --- src/mlpack/core/data/split_data.hpp | 4 +--- src/mlpack/tests/split_data_test.cpp | 30 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index aedb2ad3b4..23c88c1c2b 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -137,13 +137,11 @@ void Split(const arma::Mat& input, if (trainSize > 0) trainData = input.cols(order.subvec(0, trainSize - 1)); - if (trainSize < input.n_cols) + if (trainSize < input.n_cols) testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); - } else { - if (trainSize > 0) trainData = input.cols(0, trainSize - 1); diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index d8adf14c0a..80464e2676 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -123,6 +123,36 @@ BOOST_AUTO_TEST_CASE(SplitDataResultMat) CheckMatrices(input, concat); } +BOOST_AUTO_TEST_CASE(ZeroRatioSplitData) +{ + mat input(2, 10); + size_t count = 0; // Counter for unique sequential values. + input.imbue([&count] () { return ++count; }); + + const auto value = Split(input, 0, false); + BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 10); // Train data. + BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 0); // Test data. + + mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); + // Order matters here. + CheckMatrices(input, concat); +} + +BOOST_AUTO_TEST_CASE(TotalRatioSplitData) +{ + mat input(2, 10); + size_t count = 0; // Counter for unique sequential values. + input.imbue([&count] () { return ++count; }); + + const auto value = Split(input, 1, false); + BOOST_REQUIRE_EQUAL(std::get<0>(value).n_cols, 0); // Train data. + BOOST_REQUIRE_EQUAL(std::get<1>(value).n_cols, 10); // Test data. + + mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); + // Order matters here. + CheckMatrices(input, concat); +} + BOOST_AUTO_TEST_CASE(SplitLabeledDataResultMat) { mat input(2, 10);