mirror of
https://github.com/Doctorado-ML/FImdlp.git
synced 2025-08-16 07:55:52 +00:00
test: ⚡
This commit is contained in:
@@ -24,8 +24,8 @@ git clone --recurse-submodules https://github.com/doctorado-ml/FImdlp.git
|
||||
|
||||
```bash
|
||||
pip install -e .
|
||||
python samples/sample.py iris --original
|
||||
python samples/sample.py iris --proposal
|
||||
python samples/sample.py iris
|
||||
python samples/sample.py iris --alternative
|
||||
python samples/sample.py -h # for more options
|
||||
```
|
||||
|
||||
|
@@ -1,117 +0,0 @@
|
||||
#include "ArffFiles.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
ArffFiles::ArffFiles()
|
||||
{
|
||||
}
|
||||
vector<string> ArffFiles::getLines()
|
||||
{
|
||||
return lines;
|
||||
}
|
||||
unsigned long int ArffFiles::getSize()
|
||||
{
|
||||
return lines.size();
|
||||
}
|
||||
vector<tuple<string, string>> ArffFiles::getAttributes()
|
||||
{
|
||||
return attributes;
|
||||
}
|
||||
string ArffFiles::getClassName()
|
||||
{
|
||||
return className;
|
||||
}
|
||||
string ArffFiles::getClassType()
|
||||
{
|
||||
return classType;
|
||||
}
|
||||
vector<vector<float>>& ArffFiles::getX()
|
||||
{
|
||||
return X;
|
||||
}
|
||||
vector<int>& ArffFiles::getY()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
void ArffFiles::load(string fileName, bool classLast)
|
||||
{
|
||||
ifstream file(fileName);
|
||||
string keyword, attribute, type;
|
||||
if (file.is_open()) {
|
||||
string line;
|
||||
while (getline(file, line)) {
|
||||
if (line[0] == '%' || line.empty() || line == "\r" || line == " ") {
|
||||
continue;
|
||||
}
|
||||
if (line.find("@attribute") != string::npos || line.find("@ATTRIBUTE") != string::npos) {
|
||||
stringstream ss(line);
|
||||
ss >> keyword >> attribute >> type;
|
||||
attributes.push_back(make_tuple(attribute, type));
|
||||
continue;
|
||||
}
|
||||
if (line[0] == '@') {
|
||||
continue;
|
||||
}
|
||||
lines.push_back(line);
|
||||
}
|
||||
file.close();
|
||||
if (attributes.empty())
|
||||
throw invalid_argument("No attributes found");
|
||||
if (classLast) {
|
||||
className = get<0>(attributes.back());
|
||||
classType = get<1>(attributes.back());
|
||||
attributes.pop_back();
|
||||
} else {
|
||||
className = get<0>(attributes.front());
|
||||
classType = get<1>(attributes.front());
|
||||
attributes.erase(attributes.begin());
|
||||
}
|
||||
generateDataset(classLast);
|
||||
} else
|
||||
throw invalid_argument("Unable to open file");
|
||||
}
|
||||
void ArffFiles::generateDataset(bool classLast)
|
||||
{
|
||||
X = vector<vector<float>>(attributes.size(), vector<float>(lines.size()));
|
||||
vector<string> yy = vector<string>(lines.size(), "");
|
||||
int labelIndex = classLast ? attributes.size() : 0;
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
stringstream ss(lines[i]);
|
||||
string value;
|
||||
int pos = 0, xIndex = 0;
|
||||
while (getline(ss, value, ',')) {
|
||||
if (pos++ == labelIndex) {
|
||||
yy[i] = value;
|
||||
} else {
|
||||
X[xIndex++][i] = stof(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
y = factorize(yy);
|
||||
}
|
||||
string ArffFiles::trim(const string& source)
|
||||
{
|
||||
string s(source);
|
||||
s.erase(0, s.find_first_not_of(" \n\r\t"));
|
||||
s.erase(s.find_last_not_of(" \n\r\t") + 1);
|
||||
return s;
|
||||
}
|
||||
vector<int> ArffFiles::factorize(const vector<string>& labels_t)
|
||||
{
|
||||
vector<int> yy;
|
||||
yy.reserve(labels_t.size());
|
||||
map<string, int> labelMap;
|
||||
int i = 0;
|
||||
for (string label : labels_t) {
|
||||
if (labelMap.find(label) == labelMap.end()) {
|
||||
labelMap[label] = i++;
|
||||
}
|
||||
yy.push_back(labelMap[label]);
|
||||
}
|
||||
return yy;
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
#ifndef ARFFFILES_H
|
||||
#define ARFFFILES_H
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
using namespace std;
|
||||
class ArffFiles {
|
||||
private:
|
||||
vector<string> lines;
|
||||
vector<tuple<string, string>> attributes;
|
||||
string className, classType;
|
||||
vector<vector<float>> X;
|
||||
vector<int> y;
|
||||
void generateDataset(bool);
|
||||
public:
|
||||
ArffFiles();
|
||||
void load(string, bool = true);
|
||||
vector<string> getLines();
|
||||
unsigned long int getSize();
|
||||
string getClassName();
|
||||
string getClassType();
|
||||
string trim(const string&);
|
||||
vector<vector<float>>& getX();
|
||||
vector<int>& getY();
|
||||
vector<tuple<string, string>> getAttributes();
|
||||
vector<int> factorize(const vector<string>& labels_t);
|
||||
};
|
||||
#endif
|
@@ -3,4 +3,4 @@ project(main)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
add_executable(sample sample.cpp ArffFiles.cpp ../src/cppmdlp/Metrics.cpp ../src/cppmdlp/CPPFImdlp.cpp)
|
||||
add_executable(sample sample.cpp ../src/cppmdlp/tests/ArffFiles.cpp ../src/cppmdlp/Metrics.cpp ../src/cppmdlp/CPPFImdlp.cpp)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#include "ArffFiles.h"
|
||||
#include "../src/cppmdlp/tests/ArffFiles.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
|
@@ -14,10 +14,8 @@ datasets = {
|
||||
}
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--proposal", action="store_const", const=1)
|
||||
ap.add_argument("--original", dest="proposal", action="store_const", const=0)
|
||||
ap.add_argument(
|
||||
"--alternative", dest="proposal", action="store_const", const=2
|
||||
"--alternative", dest="proposal", action="store_const", const=1
|
||||
)
|
||||
ap.add_argument("dataset", type=str, choices=datasets.keys())
|
||||
args = ap.parse_args()
|
||||
@@ -32,7 +30,7 @@ class_name = df.columns.to_list()[class_column]
|
||||
X = df.drop(class_name, axis=1)
|
||||
y, _ = pd.factorize(df[class_name])
|
||||
X = X.to_numpy()
|
||||
test = FImdlp(proposal=args.proposal)
|
||||
test = FImdlp(algorithm=args.proposal if args.proposal is not None else 0)
|
||||
now = time.time()
|
||||
test.fit(X, y)
|
||||
fit_time = time.time()
|
||||
|
Submodule src/cppmdlp updated: 50543e4921...35c532bf1d
@@ -14,8 +14,8 @@ cdef extern from "../cppmdlp/CPPFImdlp.h" namespace "mdlp":
|
||||
|
||||
cdef class CFImdlp:
|
||||
cdef CPPFImdlp *thisptr
|
||||
def __cinit__(self, proposal):
|
||||
self.thisptr = new CPPFImdlp(proposal)
|
||||
def __cinit__(self, algorithm):
|
||||
self.thisptr = new CPPFImdlp(algorithm)
|
||||
def __dealloc__(self):
|
||||
del self.thisptr
|
||||
def fit(self, X, y):
|
||||
|
@@ -7,23 +7,22 @@ from joblib import Parallel, delayed
|
||||
|
||||
|
||||
class FImdlp(TransformerMixin, BaseEstimator):
|
||||
def __init__(self, n_jobs=-1, proposal=0):
|
||||
def __init__(self, algorithm=0, n_jobs=-1):
|
||||
self.algorithm = algorithm
|
||||
self.n_jobs = n_jobs
|
||||
self.proposal = proposal
|
||||
|
||||
"""Fayyad - Irani MDLP discretization algorithm based implementation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
algorithm : int, default=0
|
||||
The type of algorithm to use computing the cut points.
|
||||
0 - Definitive implementation
|
||||
1 - Alternative proposal
|
||||
n_jobs : int, default=-1
|
||||
The number of jobs to run in parallel. :meth:`fit` and
|
||||
:meth:`transform`, are parallelized over the features. ``-1`` means
|
||||
using all cores available.
|
||||
proposal : int, default=0
|
||||
The type of algorithm to use computing the cut points.
|
||||
0 - Normal implementation
|
||||
1 - JA Proposal
|
||||
2 - Original proposal
|
||||
|
||||
Attributes
|
||||
----------
|
||||
@@ -100,7 +99,7 @@ class FImdlp(TransformerMixin, BaseEstimator):
|
||||
|
||||
def _fit_discretizer(self, feature):
|
||||
if feature in self.features_:
|
||||
self.discretizer_[feature] = CFImdlp(proposal=self.proposal)
|
||||
self.discretizer_[feature] = CFImdlp(algorithm=self.algorithm)
|
||||
self.discretizer_[feature].fit(self.X_[:, feature], self.y_)
|
||||
self.cut_points_[feature] = self.discretizer_[
|
||||
feature
|
||||
@@ -136,7 +135,10 @@ class FImdlp(TransformerMixin, BaseEstimator):
|
||||
raise ValueError(
|
||||
"Shape of input is different from what was seen in `fit`"
|
||||
)
|
||||
result = np.zeros_like(X, dtype=np.int32) - 1
|
||||
if len(self.features_) == self.n_features_:
|
||||
result = np.zeros_like(X, dtype=np.int32) - 1
|
||||
else:
|
||||
result = np.zeros_like(X) - 1
|
||||
Parallel(n_jobs=self.n_jobs, prefer="threads")(
|
||||
delayed(self._discretize_feature)(feature, X[:, feature], result)
|
||||
for feature in range(self.n_features_)
|
||||
|
@@ -14,47 +14,41 @@ class FImdlpTest(unittest.TestCase):
|
||||
def test_init(self):
|
||||
clf = FImdlp()
|
||||
self.assertEqual(-1, clf.n_jobs)
|
||||
self.assertEqual(0, clf.proposal)
|
||||
clf = FImdlp(proposal=1, n_jobs=7)
|
||||
self.assertEqual(1, clf.proposal)
|
||||
self.assertEqual(0, clf.algorithm)
|
||||
clf = FImdlp(algorithm=1, n_jobs=7)
|
||||
self.assertEqual(1, clf.algorithm)
|
||||
self.assertEqual(7, clf.n_jobs)
|
||||
|
||||
def test_fit_proposal(self):
|
||||
clf = FImdlp(proposal=1)
|
||||
def test_fit_definitive(self):
|
||||
clf = FImdlp(algorithm=0)
|
||||
clf.fit([[1, 2], [3, 4]], [1, 2])
|
||||
self.assertEqual(clf.n_features_, 2)
|
||||
self.assertListEqual(clf.X_.tolist(), [[1, 2], [3, 4]])
|
||||
self.assertListEqual(clf.y_.tolist(), [1, 2])
|
||||
self.assertListEqual([[], []], clf.get_cut_points())
|
||||
self.assertListEqual([[2.0], [3.0]], clf.get_cut_points())
|
||||
X, y = load_iris(return_X_y=True)
|
||||
clf.fit(X, y)
|
||||
self.assertEqual(clf.n_features_, 4)
|
||||
self.assertTrue(np.array_equal(X, clf.X_))
|
||||
self.assertTrue(np.array_equal(y, clf.y_))
|
||||
expected = [
|
||||
[
|
||||
4.900000095367432,
|
||||
5.0,
|
||||
5.099999904632568,
|
||||
5.400000095367432,
|
||||
5.699999809265137,
|
||||
],
|
||||
[2.6999998092651367, 2.9000000953674316, 3.1999998092651367],
|
||||
[2.3499999046325684, 4.5, 4.800000190734863],
|
||||
[0.75, 1.399999976158142, 1.5, 1.7000000476837158],
|
||||
[5.449999809265137, 6.25],
|
||||
[2.8499999046325684, 3.0, 3.049999952316284, 3.3499999046325684],
|
||||
[2.450000047683716, 4.75, 5.050000190734863],
|
||||
[0.800000011920929, 1.4500000476837158, 1.75],
|
||||
]
|
||||
self.assertListEqual(expected, clf.get_cut_points())
|
||||
self.assertListEqual([0, 1, 2, 3], clf.features_)
|
||||
clf.fit(X, y, features=[0, 2, 3])
|
||||
self.assertListEqual([0, 2, 3], clf.features_)
|
||||
|
||||
def test_fit_original(self):
|
||||
clf = FImdlp(proposal=0)
|
||||
def test_fit_alternative(self):
|
||||
clf = FImdlp(algorithm=1)
|
||||
clf.fit([[1, 2], [3, 4]], [1, 2])
|
||||
self.assertEqual(clf.n_features_, 2)
|
||||
self.assertListEqual(clf.X_.tolist(), [[1, 2], [3, 4]])
|
||||
self.assertListEqual(clf.y_.tolist(), [1, 2])
|
||||
self.assertListEqual([[], []], clf.get_cut_points())
|
||||
self.assertListEqual([[2], [3]], clf.get_cut_points())
|
||||
X, y = load_iris(return_X_y=True)
|
||||
clf.fit(X, y)
|
||||
self.assertEqual(clf.n_features_, 4)
|
||||
@@ -62,10 +56,10 @@ class FImdlpTest(unittest.TestCase):
|
||||
self.assertTrue(np.array_equal(y, clf.y_))
|
||||
|
||||
expected = [
|
||||
[5.5, 5.800000190734863],
|
||||
[2.9000000953674316, 3.3499999046325684],
|
||||
[2.450000047683716, 4.800000190734863],
|
||||
[0.800000011920929, 1.7999999523162842],
|
||||
[5.449999809265137, 5.75],
|
||||
[2.8499999046325684, 3.3499999046325684],
|
||||
[2.450000047683716, 4.75],
|
||||
[0.800000011920929, 1.75],
|
||||
]
|
||||
self.assertListEqual(expected, clf.get_cut_points())
|
||||
self.assertListEqual([0, 1, 2, 3], clf.features_)
|
||||
@@ -89,45 +83,58 @@ class FImdlpTest(unittest.TestCase):
|
||||
|
||||
def test_fit_features(self):
|
||||
clf = FImdlp()
|
||||
clf.fit([[1, 2], [3, 4]], [1, 2], features=[0])
|
||||
res = clf.transform([[1, 2], [3, 4]])
|
||||
self.assertListEqual(res.tolist(), [[0, 2], [0, 4]])
|
||||
clf.fit([[1, -2], [3, 4]], [1, 2], features=[0])
|
||||
res = clf.transform([[1, -2], [3, 4]])
|
||||
self.assertListEqual(res.tolist(), [[0, -2], [1, 4]])
|
||||
X, y = load_iris(return_X_y=True)
|
||||
X_expected = X[:, [0, 2]].copy()
|
||||
clf.fit(X, y, features=[1, 3])
|
||||
X_computed = clf.transform(X)
|
||||
self.assertListEqual(
|
||||
X_expected[:, 0].tolist(), X_computed[:, 0].tolist()
|
||||
)
|
||||
self.assertListEqual(
|
||||
X_expected[:, 1].tolist(), X_computed[:, 2].tolist()
|
||||
)
|
||||
self.assertEqual(X_computed.dtype, np.float64)
|
||||
|
||||
def test_transform_original(self):
|
||||
clf = FImdlp(proposal=0)
|
||||
def test_transform_definitive(self):
|
||||
clf = FImdlp(algorithm=0)
|
||||
clf.fit([[1, 2], [3, 4]], [1, 2])
|
||||
self.assertEqual(
|
||||
clf.transform([[1, 2], [3, 4]]).tolist(), [[0, 0], [0, 0]]
|
||||
clf.transform([[1, 2], [3, 4]]).tolist(), [[0, 0], [1, 1]]
|
||||
)
|
||||
X, y = load_iris(return_X_y=True)
|
||||
clf.fit(X, y)
|
||||
self.assertEqual(clf.n_features_, 4)
|
||||
self.assertTrue(np.array_equal(X, clf.X_))
|
||||
self.assertTrue(np.array_equal(y, clf.y_))
|
||||
X_transformed = clf.transform(X)
|
||||
self.assertListEqual(
|
||||
clf.transform(X).tolist(), clf.fit(X, y).transform(X).tolist()
|
||||
X_transformed.tolist(), clf.fit(X, y).transform(X).tolist()
|
||||
)
|
||||
self.assertEqual(X_transformed.dtype, np.int32)
|
||||
expected = [
|
||||
[0, 0, 1, 1],
|
||||
[2, 1, 1, 1],
|
||||
[1, 0, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 0, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
[1, 0, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 0, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
]
|
||||
self.assertTrue(np.array_equal(clf.transform(X[90:97]), expected))
|
||||
with self.assertRaises(ValueError):
|
||||
clf.transform([[1, 2, 3], [4, 5, 6]])
|
||||
with self.assertRaises(sklearn.exceptions.NotFittedError):
|
||||
clf = FImdlp(proposal=0)
|
||||
clf = FImdlp(algorithm=0)
|
||||
clf.transform([[1, 2], [3, 4]])
|
||||
|
||||
def test_transform_proposal(self):
|
||||
clf = FImdlp(proposal=1)
|
||||
def test_transform_alternative(self):
|
||||
clf = FImdlp(algorithm=1)
|
||||
clf.fit([[1, 2], [3, 4]], [1, 2])
|
||||
self.assertEqual(
|
||||
clf.transform([[1, 2], [3, 4]]).tolist(), [[0, 0], [0, 0]]
|
||||
clf.transform([[1, 2], [3, 4]]).tolist(), [[0, 0], [1, 1]]
|
||||
)
|
||||
X, y = load_iris(return_X_y=True)
|
||||
clf.fit(X, y)
|
||||
@@ -138,17 +145,17 @@ class FImdlpTest(unittest.TestCase):
|
||||
clf.transform(X).tolist(), clf.fit(X, y).transform(X).tolist()
|
||||
)
|
||||
expected = [
|
||||
[4, 0, 1, 1],
|
||||
[5, 2, 2, 2],
|
||||
[5, 0, 1, 1],
|
||||
[1, 0, 1, 1],
|
||||
[4, 1, 1, 1],
|
||||
[5, 2, 1, 1],
|
||||
[5, 1, 1, 1],
|
||||
[2, 1, 1, 1],
|
||||
[2, 0, 1, 1],
|
||||
[0, 0, 1, 1],
|
||||
[1, 0, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
[1, 1, 1, 1],
|
||||
]
|
||||
self.assertTrue(np.array_equal(clf.transform(X[90:97]), expected))
|
||||
with self.assertRaises(ValueError):
|
||||
clf.transform([[1, 2, 3], [4, 5, 6]])
|
||||
with self.assertRaises(sklearn.exceptions.NotFittedError):
|
||||
clf = FImdlp(proposal=1)
|
||||
clf = FImdlp(algorithm=1)
|
||||
clf.transform([[1, 2], [3, 4]])
|
||||
|
Reference in New Issue
Block a user