Categorical support preprocess_one_hot_encoding (#3487)
This commit is contained in:
+6
-1
@@ -4,7 +4,12 @@
|
||||
|
||||
* Fix bug in LogSoftMax derivative (#3469).
|
||||
|
||||
* Add `serialize` method to `GaussianInitialization`, `KathirvalavakumarSubavathiInitialization`, `KathirvalavakumarSubavathiInitialization`, `NguyenWidrowInitialization`, and `OrthogonalInitialization` (#3483).
|
||||
* Add `serialize` method to `GaussianInitialization`,
|
||||
`KathirvalavakumarSubavathiInitialization`,
|
||||
`KathirvalavakumarSubavathiInitialization`, `NguyenWidrowInitialization`,
|
||||
and `OrthogonalInitialization` (#3483).
|
||||
|
||||
* Allow categorical features to `preprocess_one_hot_encode` (#3487).
|
||||
|
||||
* Install mlpack and cereal headers as part of R package (#3488).
|
||||
|
||||
|
||||
@@ -488,9 +488,9 @@ void PrintInputProcessing(
|
||||
{
|
||||
std::cout << prefix << "cdef extern from \"numpy/arrayobject.h\":" << std::endl;
|
||||
std::cout << prefix << " void* PyArray_DATA(np.ndarray arr)" << std::endl;
|
||||
std::cout << prefix << "if " << d.name << " is not None:" << std::endl;
|
||||
std::cout << prefix << " " << d.name << "_tuple = to_matrix_with_info("
|
||||
<< d.name << ", dtype=np.double, copy=p.Has('copy_all_inputs'))"
|
||||
std::cout << prefix << "if " << name << " is not None:" << std::endl;
|
||||
std::cout << prefix << " " << name << "_tuple = to_matrix_with_info("
|
||||
<< name << ", dtype=np.double, copy=p.Has('copy_all_inputs'))"
|
||||
<< std::endl;
|
||||
std::cout << prefix << " if len(" << name << "_tuple[0].shape"
|
||||
<< ") < 2:" << std::endl;
|
||||
@@ -501,8 +501,8 @@ void PrintInputProcessing(
|
||||
std::cout << prefix << " " << name << "_dims = " << name
|
||||
<< "_tuple[2]" << std::endl;
|
||||
std::cout << prefix << " SetParamWithInfo[arma.Mat[double]](p, <const "
|
||||
<< "string> '" << d.name << "', dereference(" << d.name << "_mat), "
|
||||
<< "<const cbool*> PyArray_DATA(" << d.name << "_dims))" << std::endl;
|
||||
<< "string> '" << d.name << "', dereference(" << name << "_mat), "
|
||||
<< "<const cbool*> PyArray_DATA(" << name << "_dims))" << std::endl;
|
||||
std::cout << prefix << " p.SetPassed(<const string> '" << d.name
|
||||
<< "')" << std::endl;
|
||||
std::cout << prefix << " del " << name << "_mat" << std::endl;
|
||||
@@ -511,7 +511,7 @@ void PrintInputProcessing(
|
||||
{
|
||||
std::cout << prefix << "cdef extern from \"numpy/arrayobject.h\":" << std::endl;
|
||||
std::cout << prefix << " void* PyArray_DATA(np.ndarray arr)" << std::endl;
|
||||
std::cout << prefix << d.name << "_tuple = to_matrix_with_info(" << d.name
|
||||
std::cout << prefix << name << "_tuple = to_matrix_with_info(" << name
|
||||
<< ", dtype=np.double, copy=p.Has('copy_all_inputs'))"
|
||||
<< std::endl;
|
||||
std::cout << prefix << "if len(" << name << "_tuple[0].shape"
|
||||
@@ -523,8 +523,8 @@ void PrintInputProcessing(
|
||||
std::cout << prefix << name << "_dims = " << name << "_tuple[2]"
|
||||
<< std::endl;
|
||||
std::cout << prefix << "SetParamWithInfo[arma.Mat[double]](p, <const "
|
||||
<< "string> '" << d.name << "', dereference(" << d.name << "_mat), "
|
||||
<< "<const cbool*> PyArray_DATA(" << d.name << "_dims))" << std::endl;
|
||||
<< "string> '" << d.name << "', dereference(" << name << "_mat), "
|
||||
<< "<const cbool*> PyArray_DATA(" << name << "_dims))" << std::endl;
|
||||
std::cout << prefix << "p.SetPassed(<const string> '" << d.name << "')"
|
||||
<< std::endl;
|
||||
std::cout << prefix << "del " << name << "_mat" << std::endl;
|
||||
|
||||
@@ -330,7 +330,7 @@
|
||||
|
||||
/**
|
||||
* Define a matrix output parameter. When the program terminates, the matrix
|
||||
* will be saved to whatever it was set to by IO::GetParam<arma::mat>(ID)
|
||||
* will be saved to whatever it was set to by params.Get<arma::mat>(ID)
|
||||
* during the program. From the command-line, the user may specify the file in
|
||||
* which to save the output matrix using a string option that is the name of the
|
||||
* matrix parameter with "_file" appended. So, for instance, if the name of the
|
||||
@@ -400,7 +400,7 @@
|
||||
* Define a transposed matrix output parameter. This is useful when data is
|
||||
* stored in a row-major form instead of the usual column-major form. When the
|
||||
* program terminates, the matrix will be saved to whatever it was set to by
|
||||
* IO::GetParam<arma::mat>(ID) during the program. From the command-line, the
|
||||
* params.Get<arma::mat>(ID) during the program. From the command-line, the
|
||||
* user may specify the file in which to save the output matrix using a string
|
||||
* option that is the name of the matrix parameter with "_file" appended. So,
|
||||
* for instance, if the name of the output matrix parameter was "mat", the user
|
||||
@@ -467,7 +467,7 @@
|
||||
/**
|
||||
* Define an unsigned matrix output parameter (arma::Mat<size_t>). When the
|
||||
* program terminates, the matrix will be saved to whatever it was set to by
|
||||
* IO::GetParam<arma::Mat<size_t>>(ID) during the program. From the
|
||||
* params.Get<arma::Mat<size_t>>(ID) during the program. From the
|
||||
* command-line, the user may specify the file in which to save the output
|
||||
* matrix using a string option that is the name of the matrix parameter with
|
||||
* "_file" appended. So, for instance, if the name of the output matrix
|
||||
@@ -746,9 +746,9 @@
|
||||
*
|
||||
* @code
|
||||
* DatasetInfo d = std::move(
|
||||
* IO::GetParam<std::tuple<DatasetInfo, arma::mat>>("matrix").get<0>());
|
||||
* params.Get<std::tuple<DatasetInfo, arma::mat>>("matrix").get<0>());
|
||||
* arma::mat m = std::move(
|
||||
* IO::GetParam<std::tuple<DatasetInfo, arma::mat>>("matrix").get<1>());
|
||||
* params.Get<std::tuple<DatasetInfo, arma::mat>>("matrix").get<1>());
|
||||
* @endcode
|
||||
*
|
||||
* @param ID Name of the parameter.
|
||||
@@ -763,6 +763,38 @@
|
||||
"std::tuple<mlpack::data::DatasetInfo, arma::mat>", false, true, true, \
|
||||
TUPLE_TYPE())
|
||||
|
||||
/**
|
||||
* Define a required input DatasetInfo/matrix parameter. From the command line,
|
||||
* the user can specify the file that holds the matrix, using the name of the
|
||||
* matrix parameter with "_file" appended (and the same alias). So for
|
||||
* instance, if the name of the matrix parameter was "matrix", the user could
|
||||
* specify that the "matrix" matrix was held in file.csv by giving the parameter
|
||||
*
|
||||
* @code
|
||||
* --matrix_file file.csv
|
||||
* @endcode
|
||||
*
|
||||
* Then the DatasetInfo and matrix type could be accessed with
|
||||
*
|
||||
* @code
|
||||
* DatasetInfo d = std::move(
|
||||
* params.Get<std::tuple<DatasetInfo, arma::mat>>("matrix").get<0>());
|
||||
* arma::mat m = std::move(
|
||||
* params.Get<std::tuple<DatasetInfo, arma::mat>>("matrix").get<1>());
|
||||
* @endcode
|
||||
*
|
||||
* @param ID Name of the parameter.
|
||||
* @param DESC Quick description of the parameter (1-2 sentences). Don't use
|
||||
* printing macros like PRINT_PARAM_STRING() or PRINT_DATASET() or others
|
||||
* here---it will cause problems.
|
||||
* @param ALIAS One-character string representing the alias of the parameter.
|
||||
*/
|
||||
#define TUPLE_TYPE std::tuple<mlpack::data::DatasetInfo, arma::mat>
|
||||
#define PARAM_MATRIX_AND_INFO_IN_REQ(ID, DESC, ALIAS) \
|
||||
PARAM(TUPLE_TYPE, ID, DESC, ALIAS, \
|
||||
"std::tuple<mlpack::data::DatasetInfo, arma::mat>", true, true, true, \
|
||||
TUPLE_TYPE())
|
||||
|
||||
/**
|
||||
* Define an input model. From the command line, the user can specify the file
|
||||
* that holds the model, using the name of the model parameter with "_file"
|
||||
@@ -836,9 +868,7 @@
|
||||
* --model_file model.bin
|
||||
* @endcode
|
||||
*
|
||||
* The model will be saved at the termination of the program. If you use a
|
||||
* parameter of this type, you must call IO::Destroy() at the end of your
|
||||
* program.
|
||||
* The model will be saved at the termination of the program.
|
||||
*
|
||||
* @param TYPE Type of the model to be saved.
|
||||
* @param ID Name of the parameter.
|
||||
|
||||
@@ -28,6 +28,11 @@ BINDING_LONG_DESC(
|
||||
"encoding of the respective features at those indices. Indices represent "
|
||||
"the IDs of the dimensions to be one-hot encoded."
|
||||
"\n\n"
|
||||
"If no dimensions are specified with " + PRINT_PARAM_STRING("dimensions") +
|
||||
", then all categorical-type dimensions will be one-hot encoded. "
|
||||
"Otherwise, only the dimensions given in " +
|
||||
PRINT_PARAM_STRING("dimensions") + " will be one-hot encoded."
|
||||
"\n\n"
|
||||
"The output matrix with encoded features may be saved with the " +
|
||||
PRINT_PARAM_STRING("output") + " parameters.");
|
||||
|
||||
@@ -48,12 +53,13 @@ BINDING_SEE_ALSO("One-hot encoding on Wikipedia",
|
||||
"https://en.m.wikipedia.org/wiki/One-hot");
|
||||
|
||||
// Define parameters for data.
|
||||
PARAM_MATRIX_IN_REQ("input", "Matrix containing data.", "i");
|
||||
PARAM_MATRIX_AND_INFO_IN_REQ("input", "Matrix containing data.", "i");
|
||||
PARAM_MATRIX_OUT("output", "Matrix to save one-hot encoded features "
|
||||
"data to.", "o");
|
||||
|
||||
PARAM_VECTOR_IN_REQ(int, "dimensions", "Index of dimensions that"
|
||||
"need to be one-hot encoded.", "d");
|
||||
PARAM_VECTOR_IN(int, "dimensions", "Index of dimensions that need to be one-hot"
|
||||
" encoded (if unspecified, all categorical dimensions are one-hot "
|
||||
"encoded).", "d");
|
||||
|
||||
using namespace mlpack;
|
||||
using namespace mlpack::util;
|
||||
@@ -63,29 +69,65 @@ using namespace std;
|
||||
void BINDING_FUNCTION(util::Params& params, util::Timers& /* timers */)
|
||||
{
|
||||
// Load the data.
|
||||
const arma::mat& data = params.Get<arma::mat>("input");
|
||||
vector<int>& indices = params.Get<vector<int> >("dimensions");
|
||||
vector<size_t> copyIndices(indices.size());
|
||||
RequireParamValue<std::vector<int>>(params, "dimensions",
|
||||
[data](std::vector<int> x)
|
||||
{
|
||||
for (int dim : x)
|
||||
{
|
||||
if (dim < 0 || (size_t)dim > data.n_rows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, true, "dimensions must be greater than 0 and less than the number of "
|
||||
"dimensions");
|
||||
const std::tuple<data::DatasetInfo, arma::mat>& t =
|
||||
params.Get<std::tuple<data::DatasetInfo, arma::mat>>("input");
|
||||
|
||||
for (size_t i = 0; i < indices.size(); ++i)
|
||||
const data::DatasetInfo& info = std::get<0>(t);
|
||||
const arma::mat& data = std::get<1>(t);
|
||||
|
||||
vector<int>& indices = params.Get<vector<int>>("dimensions");
|
||||
if (!params.Has("dimensions"))
|
||||
{
|
||||
copyIndices[i] = (size_t)indices[i];
|
||||
// If the user did not specify any dimensions to convert, we pick all the
|
||||
// categorical dimensions by default.
|
||||
for (size_t d = 0; d < info.Dimensionality(); ++d)
|
||||
if (info.Type(d) == data::Datatype::categorical)
|
||||
indices.push_back(d);
|
||||
|
||||
// Print which dimensions we selected to one-hot encode.
|
||||
if (indices.size() > 0)
|
||||
{
|
||||
Log::Info << "One-hot encoding categorical dimensions: [";
|
||||
for (size_t i = 0; i < indices.size() - 1; ++i)
|
||||
Log::Info << indices[i] << ", ";
|
||||
Log::Info << indices[indices.size() - 1] << "]." << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the user did specify dimensions, let's make sure they are reasonable.
|
||||
RequireParamValue<std::vector<int>>(params, "dimensions",
|
||||
[data](std::vector<int> x)
|
||||
{
|
||||
for (int dim : x)
|
||||
{
|
||||
if (dim < 0 || (size_t) dim > data.n_rows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, true, "dimensions must be greater than 0 and less than the number of"
|
||||
" dimensions");
|
||||
}
|
||||
|
||||
// Note that it's possible that zero dimensions are selected for one-hot
|
||||
// encoding.
|
||||
if (indices.size() > 0)
|
||||
{
|
||||
vector<size_t> copyIndices(indices.size());
|
||||
for (size_t i = 0; i < indices.size(); ++i)
|
||||
{
|
||||
copyIndices[i] = (size_t)indices[i];
|
||||
}
|
||||
|
||||
arma::mat output;
|
||||
data::OneHotEncoding(data, (arma::Col<size_t>)(copyIndices), output);
|
||||
if (params.Has("output"))
|
||||
params.Get<arma::mat>("output") = std::move(output);
|
||||
}
|
||||
else if (params.Has("output"))
|
||||
{
|
||||
params.Get<arma::mat>("output") = data; // Copy input to output.
|
||||
}
|
||||
arma::mat output;
|
||||
data::OneHotEncoding(data, (arma::Col<size_t>)(copyIndices), output);
|
||||
if (params.Has("output"))
|
||||
params.Get<arma::mat>("output") = std::move(output);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@ TEST_CASE_METHOD(
|
||||
"0 1 0 0 0 0 1 0;"
|
||||
"1 1 -1 -1 -1 -1 1 1;";
|
||||
|
||||
SetInputParam("input", dataset);
|
||||
data::DatasetInfo di(dataset.n_rows);
|
||||
SetInputParam("input", std::make_tuple(di, dataset));
|
||||
SetInputParam<vector<int>>("dimensions", {1, 3});
|
||||
RUN_BINDING();
|
||||
|
||||
@@ -66,7 +67,8 @@ TEST_CASE_METHOD(
|
||||
{
|
||||
arma::mat dataset;
|
||||
|
||||
SetInputParam("input", dataset);
|
||||
data::DatasetInfo di(dataset.n_rows);
|
||||
SetInputParam("input", std::make_tuple(di, dataset));
|
||||
SetInputParam<vector<int>>("dimensions", {1, 3});
|
||||
// This will throw an error since dimensions are bigger than the matrix.
|
||||
REQUIRE_THROWS_AS(RUN_BINDING(), std::runtime_error);
|
||||
@@ -86,7 +88,8 @@ TEST_CASE_METHOD(
|
||||
"-1 1 -1 -1 -1 -1 1 -1;"
|
||||
"1 1 -1 -1 -1 -1 1 1;";
|
||||
|
||||
SetInputParam("input", dataset);
|
||||
data::DatasetInfo di(dataset.n_rows);
|
||||
SetInputParam("input", std::make_tuple(di, dataset));
|
||||
SetInputParam<vector<int>>("dimensions", {});
|
||||
RUN_BINDING();
|
||||
|
||||
@@ -110,7 +113,8 @@ TEST_CASE_METHOD(
|
||||
"-1 1 -1 -1 -1 -1 1 -1;"
|
||||
"1 1 -1 -1 -1 -1 1 1;";
|
||||
|
||||
SetInputParam("input", dataset);
|
||||
data::DatasetInfo di(dataset.n_rows);
|
||||
SetInputParam("input", std::make_tuple(di, dataset));
|
||||
SetInputParam<vector<int>>("dimensions", {10000});
|
||||
// Error since dimensions are bigger than matrix.
|
||||
REQUIRE_THROWS_AS(RUN_BINDING(), std::runtime_error);
|
||||
@@ -130,7 +134,8 @@ TEST_CASE_METHOD(
|
||||
"-1 1 -1 -1 -1 -1 1 -1;"
|
||||
"1 1 -1 -1 -1 -1 1 1;";
|
||||
|
||||
SetInputParam("input", dataset);
|
||||
data::DatasetInfo di(dataset.n_rows);
|
||||
SetInputParam("input", std::make_tuple(di, dataset));
|
||||
SetInputParam<vector<int>>("dimensions", {-10000});
|
||||
REQUIRE_THROWS_AS(RUN_BINDING(), std::runtime_error);
|
||||
}
|
||||
@@ -143,8 +148,9 @@ TEST_CASE_METHOD(
|
||||
"[PreprocessOneHotEncodingMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat dataset;
|
||||
data::DatasetInfo di(dataset.n_rows);
|
||||
|
||||
SetInputParam("input", dataset);
|
||||
SetInputParam("input", std::make_tuple(di, dataset));
|
||||
SetInputParam<vector<int>>("dimensions", {});
|
||||
RUN_BINDING();
|
||||
|
||||
@@ -153,3 +159,274 @@ TEST_CASE_METHOD(
|
||||
REQUIRE(dataset.n_rows == output.n_rows);
|
||||
CheckMatrices(output, dataset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a dataset with categorical features, where we one-hot encode all
|
||||
* categorical features.
|
||||
*/
|
||||
TEST_CASE_METHOD(
|
||||
PreprocessOneHotEncodingTestFixture, "CategoricalMatrixTest",
|
||||
"[PreprocessOneHotEncodingMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat dataset(4, 5);
|
||||
dataset.randu();
|
||||
|
||||
// Dimension 2 will be categorical.
|
||||
dataset(2, 0) = 0;
|
||||
dataset(2, 1) = 1;
|
||||
dataset(2, 2) = 1;
|
||||
dataset(2, 3) = 2;
|
||||
dataset(2, 4) = 0;
|
||||
|
||||
data::DatasetInfo info(4);
|
||||
info.Type(2) = data::Datatype::categorical;
|
||||
(void) info.MapString<double>("0", 2);
|
||||
(void) info.MapString<double>("1", 2);
|
||||
(void) info.MapString<double>("2", 2);
|
||||
REQUIRE(info.NumMappings(2) == 3);
|
||||
|
||||
SetInputParam("input", std::make_tuple(info, dataset));
|
||||
RUN_BINDING();
|
||||
|
||||
arma::mat output = params.Get<arma::mat>("output");
|
||||
REQUIRE(dataset.n_cols == output.n_cols);
|
||||
REQUIRE(dataset.n_rows + 2 == output.n_rows);
|
||||
|
||||
// Make sure one-hot encoding was correct.
|
||||
REQUIRE(output(2, 0) == 1);
|
||||
REQUIRE(output(2, 1) == 0);
|
||||
REQUIRE(output(2, 2) == 0);
|
||||
REQUIRE(output(2, 3) == 0);
|
||||
REQUIRE(output(2, 4) == 1);
|
||||
REQUIRE(output(3, 0) == 0);
|
||||
REQUIRE(output(3, 1) == 1);
|
||||
REQUIRE(output(3, 2) == 1);
|
||||
REQUIRE(output(3, 3) == 0);
|
||||
REQUIRE(output(3, 4) == 0);
|
||||
REQUIRE(output(4, 0) == 0);
|
||||
REQUIRE(output(4, 1) == 0);
|
||||
REQUIRE(output(4, 2) == 0);
|
||||
REQUIRE(output(4, 3) == 1);
|
||||
REQUIRE(output(4, 4) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a dataset with no categorical features, where we don't specify the
|
||||
* dimensions to convert. This should convert nothing.
|
||||
*/
|
||||
TEST_CASE_METHOD(
|
||||
PreprocessOneHotEncodingTestFixture, "NoCategoricalMatrixTest",
|
||||
"[PreprocessOneHotEncodingMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat dataset(4, 5);
|
||||
dataset.randu();
|
||||
data::DatasetInfo info(4); // all numeric dimensions
|
||||
|
||||
SetInputParam("input", std::make_tuple(info, dataset));
|
||||
RUN_BINDING();
|
||||
|
||||
arma::mat output = params.Get<arma::mat>("output");
|
||||
REQUIRE(dataset.n_cols == output.n_cols);
|
||||
REQUIRE(dataset.n_rows == output.n_rows);
|
||||
CheckMatrices(output, dataset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a dataset with multiple categorical features.
|
||||
*/
|
||||
TEST_CASE_METHOD(
|
||||
PreprocessOneHotEncodingTestFixture, "MultipleFeatureCategoricalMatrixTest",
|
||||
"[PreprocessOneHotEncodingMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat dataset(4, 5);
|
||||
dataset.randu();
|
||||
|
||||
// Dimensions 0, 2, and 3 will be categorical.
|
||||
dataset(0, 0) = 0;
|
||||
dataset(0, 1) = 1;
|
||||
dataset(0, 2) = 2;
|
||||
dataset(0, 3) = 3;
|
||||
dataset(0, 4) = 3;
|
||||
dataset(2, 0) = 0;
|
||||
dataset(2, 1) = 1;
|
||||
dataset(2, 2) = 1;
|
||||
dataset(2, 3) = 2;
|
||||
dataset(2, 4) = 0;
|
||||
dataset(3, 0) = 0;
|
||||
dataset(3, 1) = 0;
|
||||
dataset(3, 2) = 1;
|
||||
dataset(3, 3) = 1;
|
||||
dataset(3, 4) = 1;
|
||||
|
||||
data::DatasetInfo info(4);
|
||||
info.Type(0) = data::Datatype::categorical;
|
||||
(void) info.MapString<double>("0", 0);
|
||||
(void) info.MapString<double>("1", 0);
|
||||
(void) info.MapString<double>("2", 0);
|
||||
(void) info.MapString<double>("3", 0);
|
||||
|
||||
info.Type(2) = data::Datatype::categorical;
|
||||
(void) info.MapString<double>("0", 2);
|
||||
(void) info.MapString<double>("1", 2);
|
||||
(void) info.MapString<double>("2", 2);
|
||||
|
||||
info.Type(3) = data::Datatype::categorical;
|
||||
(void) info.MapString<double>("0", 3);
|
||||
(void) info.MapString<double>("1", 3);
|
||||
|
||||
SetInputParam("input", std::make_tuple(info, dataset));
|
||||
RUN_BINDING();
|
||||
|
||||
arma::mat output = params.Get<arma::mat>("output");
|
||||
REQUIRE(dataset.n_cols == output.n_cols);
|
||||
REQUIRE(dataset.n_rows + 3 + 2 + 1 == output.n_rows);
|
||||
|
||||
// Make sure one-hot encoding was correct.
|
||||
REQUIRE(output(0, 0) == 1);
|
||||
REQUIRE(output(0, 1) == 0);
|
||||
REQUIRE(output(0, 2) == 0);
|
||||
REQUIRE(output(0, 3) == 0);
|
||||
REQUIRE(output(0, 4) == 0);
|
||||
REQUIRE(output(1, 0) == 0);
|
||||
REQUIRE(output(1, 1) == 1);
|
||||
REQUIRE(output(1, 2) == 0);
|
||||
REQUIRE(output(1, 3) == 0);
|
||||
REQUIRE(output(1, 4) == 0);
|
||||
REQUIRE(output(2, 0) == 0);
|
||||
REQUIRE(output(2, 1) == 0);
|
||||
REQUIRE(output(2, 2) == 1);
|
||||
REQUIRE(output(2, 3) == 0);
|
||||
REQUIRE(output(2, 4) == 0);
|
||||
REQUIRE(output(3, 0) == 0);
|
||||
REQUIRE(output(3, 1) == 0);
|
||||
REQUIRE(output(3, 2) == 0);
|
||||
REQUIRE(output(3, 3) == 1);
|
||||
REQUIRE(output(3, 4) == 1);
|
||||
|
||||
REQUIRE(output(5, 0) == 1);
|
||||
REQUIRE(output(5, 1) == 0);
|
||||
REQUIRE(output(5, 2) == 0);
|
||||
REQUIRE(output(5, 3) == 0);
|
||||
REQUIRE(output(5, 4) == 1);
|
||||
REQUIRE(output(6, 0) == 0);
|
||||
REQUIRE(output(6, 1) == 1);
|
||||
REQUIRE(output(6, 2) == 1);
|
||||
REQUIRE(output(6, 3) == 0);
|
||||
REQUIRE(output(6, 4) == 0);
|
||||
REQUIRE(output(7, 0) == 0);
|
||||
REQUIRE(output(7, 1) == 0);
|
||||
REQUIRE(output(7, 2) == 0);
|
||||
REQUIRE(output(7, 3) == 1);
|
||||
REQUIRE(output(7, 4) == 0);
|
||||
|
||||
REQUIRE(output(8, 0) == 1);
|
||||
REQUIRE(output(8, 1) == 1);
|
||||
REQUIRE(output(8, 2) == 0);
|
||||
REQUIRE(output(8, 3) == 0);
|
||||
REQUIRE(output(8, 4) == 0);
|
||||
REQUIRE(output(9, 0) == 0);
|
||||
REQUIRE(output(9, 1) == 0);
|
||||
REQUIRE(output(9, 2) == 1);
|
||||
REQUIRE(output(9, 3) == 1);
|
||||
REQUIRE(output(9, 4) == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a dataset with multiple categorical features, where we are not
|
||||
* converting them all.
|
||||
*/
|
||||
TEST_CASE_METHOD(
|
||||
PreprocessOneHotEncodingTestFixture,
|
||||
"MultipleNotAllFeatureCategoricalMatrixTest",
|
||||
"[PreprocessOneHotEncodingMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat dataset(4, 5);
|
||||
dataset.randu();
|
||||
|
||||
// Dimensions 0, 2, and 3 will be categorical, but we will only convert
|
||||
// dimensions 0 and 2.
|
||||
dataset(0, 0) = 0;
|
||||
dataset(0, 1) = 1;
|
||||
dataset(0, 2) = 2;
|
||||
dataset(0, 3) = 3;
|
||||
dataset(0, 4) = 3;
|
||||
dataset(2, 0) = 0;
|
||||
dataset(2, 1) = 1;
|
||||
dataset(2, 2) = 1;
|
||||
dataset(2, 3) = 2;
|
||||
dataset(2, 4) = 0;
|
||||
dataset(3, 0) = 0;
|
||||
dataset(3, 1) = 0;
|
||||
dataset(3, 2) = 1;
|
||||
dataset(3, 3) = 1;
|
||||
dataset(3, 4) = 1;
|
||||
|
||||
data::DatasetInfo info(4);
|
||||
info.Type(0) = data::Datatype::categorical;
|
||||
(void) info.MapString<double>("0", 0);
|
||||
(void) info.MapString<double>("1", 0);
|
||||
(void) info.MapString<double>("2", 0);
|
||||
(void) info.MapString<double>("3", 0);
|
||||
|
||||
info.Type(2) = data::Datatype::categorical;
|
||||
(void) info.MapString<double>("0", 2);
|
||||
(void) info.MapString<double>("1", 2);
|
||||
(void) info.MapString<double>("2", 2);
|
||||
|
||||
info.Type(3) = data::Datatype::categorical;
|
||||
(void) info.MapString<double>("0", 3);
|
||||
(void) info.MapString<double>("1", 3);
|
||||
|
||||
SetInputParam("input", std::make_tuple(info, dataset));
|
||||
SetInputParam<vector<int>>("dimensions", {0, 2});
|
||||
RUN_BINDING();
|
||||
|
||||
arma::mat output = params.Get<arma::mat>("output");
|
||||
REQUIRE(dataset.n_cols == output.n_cols);
|
||||
REQUIRE(dataset.n_rows + 3 + 2 == output.n_rows);
|
||||
|
||||
// Make sure one-hot encoding was correct.
|
||||
REQUIRE(output(0, 0) == 1);
|
||||
REQUIRE(output(0, 1) == 0);
|
||||
REQUIRE(output(0, 2) == 0);
|
||||
REQUIRE(output(0, 3) == 0);
|
||||
REQUIRE(output(0, 4) == 0);
|
||||
REQUIRE(output(1, 0) == 0);
|
||||
REQUIRE(output(1, 1) == 1);
|
||||
REQUIRE(output(1, 2) == 0);
|
||||
REQUIRE(output(1, 3) == 0);
|
||||
REQUIRE(output(1, 4) == 0);
|
||||
REQUIRE(output(2, 0) == 0);
|
||||
REQUIRE(output(2, 1) == 0);
|
||||
REQUIRE(output(2, 2) == 1);
|
||||
REQUIRE(output(2, 3) == 0);
|
||||
REQUIRE(output(2, 4) == 0);
|
||||
REQUIRE(output(3, 0) == 0);
|
||||
REQUIRE(output(3, 1) == 0);
|
||||
REQUIRE(output(3, 2) == 0);
|
||||
REQUIRE(output(3, 3) == 1);
|
||||
REQUIRE(output(3, 4) == 1);
|
||||
|
||||
REQUIRE(output(5, 0) == 1);
|
||||
REQUIRE(output(5, 1) == 0);
|
||||
REQUIRE(output(5, 2) == 0);
|
||||
REQUIRE(output(5, 3) == 0);
|
||||
REQUIRE(output(5, 4) == 1);
|
||||
REQUIRE(output(6, 0) == 0);
|
||||
REQUIRE(output(6, 1) == 1);
|
||||
REQUIRE(output(6, 2) == 1);
|
||||
REQUIRE(output(6, 3) == 0);
|
||||
REQUIRE(output(6, 4) == 0);
|
||||
REQUIRE(output(7, 0) == 0);
|
||||
REQUIRE(output(7, 1) == 0);
|
||||
REQUIRE(output(7, 2) == 0);
|
||||
REQUIRE(output(7, 3) == 1);
|
||||
REQUIRE(output(7, 4) == 0);
|
||||
|
||||
// Make sure we did not one-hot encode the last dimension.
|
||||
REQUIRE(output(8, 0) == 0);
|
||||
REQUIRE(output(8, 1) == 0);
|
||||
REQUIRE(output(8, 2) == 1);
|
||||
REQUIRE(output(8, 3) == 1);
|
||||
REQUIRE(output(8, 4) == 1);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ BINDING_TEST_FIXTURE(SoftmaxRegressionTestFixture);
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionOutputDimensionTest",
|
||||
"[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("trainSet.csv", inputData))
|
||||
@@ -76,7 +76,7 @@ TEST_CASE_METHOD(
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionLabelsLessDimensionTest",
|
||||
"[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("trainSet.csv", inputData))
|
||||
@@ -94,7 +94,7 @@ TEST_CASE_METHOD(
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionModelReuseTest",
|
||||
"[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("trainSet.csv", inputData))
|
||||
@@ -157,7 +157,7 @@ TEST_CASE_METHOD(
|
||||
*/
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionMaxItrTest", "[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"SoftmaxRegressionMaxItrTest", "[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("trainSet.csv", inputData))
|
||||
@@ -184,7 +184,7 @@ TEST_CASE_METHOD(
|
||||
*/
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionLambdaTest", "[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"SoftmaxRegressionLambdaTest", "[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("trainSet.csv", inputData))
|
||||
@@ -212,7 +212,7 @@ TEST_CASE_METHOD(
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionNumClassesTest",
|
||||
"[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("trainSet.csv", inputData))
|
||||
@@ -240,7 +240,7 @@ TEST_CASE_METHOD(
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionTrainingVerTest",
|
||||
"[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
arma::mat inputData;
|
||||
if (!data::Load("trainSet.csv", inputData))
|
||||
@@ -274,7 +274,7 @@ TEST_CASE_METHOD(
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionDiffLambdaTest",
|
||||
"[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
// Train SR for lambda 0.1.
|
||||
arma::mat inputData;
|
||||
@@ -340,7 +340,7 @@ TEST_CASE_METHOD(
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionDiffMaxItrTest",
|
||||
"[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
// Train SR for lambda 0.1.
|
||||
arma::mat inputData;
|
||||
@@ -406,7 +406,7 @@ TEST_CASE_METHOD(
|
||||
TEST_CASE_METHOD(
|
||||
SoftmaxRegressionTestFixture,
|
||||
"SoftmaxRegressionDiffInterceptTest",
|
||||
"[SoftmaxRegressionMainTest][BindingsTests]")
|
||||
"[SoftmaxRegressionMainTest][BindingTests]")
|
||||
{
|
||||
// Train SR with intercept.
|
||||
arma::mat inputData;
|
||||
|
||||
Reference in New Issue
Block a user