Merge pull request #2293 from jeffin143/split-shuffle
Add shuffle data paramter to data_split
This commit is contained in:
+2
-1
@@ -6,6 +6,8 @@
|
||||
|
||||
* Add adaptive max pooling and adaptive mean pooling layers (#2195).
|
||||
|
||||
* Add parameter to avoid shuffling of data in preprocess_split (#2293).
|
||||
|
||||
* Add `MatType` parameter to `LSHSearch`, allowing sparse matrices to be used
|
||||
for search (#2395).
|
||||
|
||||
@@ -105,7 +107,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).
|
||||
|
||||
@@ -44,6 +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 If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true.)
|
||||
*/
|
||||
template<typename T, typename U>
|
||||
void Split(const arma::Mat<T>& input,
|
||||
@@ -52,7 +54,8 @@ void Split(const arma::Mat<T>& input,
|
||||
arma::Mat<T>& testData,
|
||||
arma::Row<U>& trainLabel,
|
||||
arma::Row<U>& testLabel,
|
||||
const double testRatio)
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
const size_t testSize = static_cast<size_t>(input.n_cols * testRatio);
|
||||
const size_t trainSize = input.n_cols - testSize;
|
||||
@@ -61,20 +64,33 @@ void Split(const arma::Mat<T>& input,
|
||||
trainLabel.set_size(trainSize);
|
||||
testLabel.set_size(testSize);
|
||||
|
||||
const arma::Col<size_t> order =
|
||||
arma::shuffle(arma::linspace<arma::Col<size_t>>(0, input.n_cols - 1,
|
||||
input.n_cols));
|
||||
|
||||
for (size_t i = 0; i != trainSize; ++i)
|
||||
if (shuffleData)
|
||||
{
|
||||
trainData.col(i) = input.col(order[i]);
|
||||
trainLabel(i) = inputLabel(order[i]);
|
||||
arma::uvec order = arma::shuffle(arma::linspace<arma::uvec>(
|
||||
0, input.n_cols - 1, input.n_cols));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != testSize; ++i)
|
||||
else
|
||||
{
|
||||
testData.col(i) = input.col(order[i + trainSize]);
|
||||
testLabel(i) = inputLabel(order[i + trainSize]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,29 +114,39 @@ void Split(const arma::Mat<T>& 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 If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true).
|
||||
*/
|
||||
template<typename T>
|
||||
void Split(const arma::Mat<T>& input,
|
||||
arma::Mat<T>& trainData,
|
||||
arma::Mat<T>& testData,
|
||||
const double testRatio)
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
const size_t testSize = static_cast<size_t>(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<size_t> order =
|
||||
arma::shuffle(arma::linspace<arma::Col<size_t>>(0, input.n_cols -1,
|
||||
input.n_cols));
|
||||
if (shuffleData)
|
||||
{
|
||||
arma::uvec order = arma::shuffle(arma::linspace<arma::uvec>(
|
||||
0, input.n_cols - 1, input.n_cols));
|
||||
|
||||
for (size_t i = 0; i != trainSize; ++i)
|
||||
{
|
||||
trainData.col(i) = input.col(order[i]);
|
||||
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));
|
||||
}
|
||||
for (size_t i = 0; i != testSize; ++i)
|
||||
else
|
||||
{
|
||||
testData.col(i) = input.col(order[i + trainSize]);
|
||||
if (trainSize > 0)
|
||||
trainData = input.cols(0, trainSize - 1);
|
||||
|
||||
if (trainSize < input.n_cols)
|
||||
testData = input.cols(trainSize , input.n_cols - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +166,8 @@ void Split(const arma::Mat<T>& 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 If true, the sample order is shuffled; otherwise, each
|
||||
* sample is visited in linear order. (Default true).
|
||||
* @return std::tuple containing trainData (arma::Mat<T>), testData
|
||||
* (arma::Mat<T>), trainLabel (arma::Row<U>), and testLabel (arma::Row<U>).
|
||||
*/
|
||||
@@ -147,7 +175,8 @@ template<typename T, typename U>
|
||||
std::tuple<arma::Mat<T>, arma::Mat<T>, arma::Row<U>, arma::Row<U>>
|
||||
Split(const arma::Mat<T>& input,
|
||||
const arma::Row<U>& inputLabel,
|
||||
const double testRatio)
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
arma::Mat<T> trainData;
|
||||
arma::Mat<T> testData;
|
||||
@@ -155,7 +184,7 @@ Split(const arma::Mat<T>& input,
|
||||
arma::Row<U> testLabel;
|
||||
|
||||
Split(input, inputLabel, trainData, testData, trainLabel, testLabel,
|
||||
testRatio);
|
||||
testRatio, shuffleData);
|
||||
|
||||
return std::make_tuple(std::move(trainData),
|
||||
std::move(testData),
|
||||
@@ -176,17 +205,20 @@ Split(const arma::Mat<T>& input,
|
||||
*
|
||||
* @param input Input dataset to split.
|
||||
* @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).
|
||||
* @return std::tuple containing trainData (arma::Mat<T>)
|
||||
* and testData (arma::Mat<T>).
|
||||
*/
|
||||
template<typename T>
|
||||
std::tuple<arma::Mat<T>, arma::Mat<T>>
|
||||
Split(const arma::Mat<T>& input,
|
||||
const double testRatio)
|
||||
const double testRatio,
|
||||
const bool shuffleData = true)
|
||||
{
|
||||
arma::Mat<T> trainData;
|
||||
arma::Mat<T> testData;
|
||||
Split(input, trainData, testData, testRatio);
|
||||
Split(input, trainData, testData, testRatio, shuffleData);
|
||||
|
||||
return std::make_tuple(std::move(trainData),
|
||||
std::move(testData));
|
||||
|
||||
@@ -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 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) +
|
||||
"\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("no_shuffle", "Avoid shuffling and splitting 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<double>("test_ratio");
|
||||
const bool shuffleData = CLI::GetParam<bool>("no_shuffle");
|
||||
|
||||
if (CLI::GetParam<int>("seed") == 0)
|
||||
mlpack::math::RandomSeed(std::time(NULL));
|
||||
@@ -129,7 +138,7 @@ static void mlpackMain()
|
||||
CLI::GetParam<arma::Mat<size_t>>("input_labels");
|
||||
arma::Row<size_t> 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."
|
||||
|
||||
@@ -199,4 +199,35 @@ BOOST_AUTO_TEST_CASE(PreprocessSplitUnityTestRatioTest)
|
||||
labelSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check shuffle_data flag is working as expected.
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE(PreprocessSplitLabelShuffleDataTest)
|
||||
{
|
||||
// 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("no_shuffle", true);
|
||||
mlpackMain();
|
||||
|
||||
// Now check that the output has desired dimensions.
|
||||
BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("training").n_cols,
|
||||
std::ceil(0.9 * inputSize));
|
||||
BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("test").n_cols,
|
||||
std::floor(0.1 * inputSize));
|
||||
|
||||
arma::mat concat = arma::join_rows(CLI::GetParam<arma::mat>("training"),
|
||||
CLI::GetParam<arma::mat>("test"));
|
||||
CheckMatrices(inputData, concat);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
@@ -94,20 +94,65 @@ void CheckDuplication(const Row<size_t>& 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
|
||||
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);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SplitDataResultMat)
|
||||
{
|
||||
mat input(2, 10);
|
||||
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.
|
||||
|
||||
mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value));
|
||||
// Order matters here.
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user