From aa6767b74958bc347c56baed8c000b4f0af2891e Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 21 Jun 2023 14:09:14 -0400 Subject: [PATCH 1/6] Fix random forest --- .gitignore | 1 + .pre-commit-config.yaml | 16 +++++ README.md | 6 +- pyproject.toml | 46 ++++++++++++++ sklearn_json/classification.py | 110 ++++++++++++--------------------- 5 files changed, 107 insertions(+), 72 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore index 3d54005..9630ec3 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ __pycache__/ build/ dist/ sklearn_json.egg-info/ +.ignore/* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5a65a8b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +exclude: "models/" +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.3.0 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace +- repo: https://github.com/psf/black + rev: 22.10.0 + hooks: + - id: black +- repo: https://github.com/charliermarsh/ruff-pre-commit + rev: 'v0.0.265' + hooks: + - id: ruff diff --git a/README.md b/README.md index a2b7337..3fc5a70 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ deserialized_model.predict(X) ``` # Features -The list of supported models is rapidly growing. If you have a request for a model or feature, please reach out to support@mlrequest.com. +The list of supported models is rapidly growing. If you have a request for a model or feature, please reach out to aheldrich@yahoo.com. sklearn-json requires scikit-learn >= 0.21.3. @@ -65,3 +65,7 @@ sklearn-json requires scikit-learn >= 0.21.3. * `sklearn.ensemble.RandomForestRegressor` * `sklearn.ensemble.GradientBoostingRegressor` * `sklearn.neural_network.MLPRegressor` + +## Upcoming + +* preproccessing diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..61e5fea --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,46 @@ +[tool.ruff] +# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. Add isort +select = ["E", "F", "I", "D"] +ignore = [] + +# Allow autofix for all enabled rules (when `--fix`) is provided. +fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"] +unfixable = [] + +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", +] + +# Same as Black. +line-length = 88 + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +# Assume Python 3.10. +target-version = "py310" + +[tool.ruff.mccabe] +# Unlike Flake8, default to a complexity level of 10. +max-complexity = 10 diff --git a/sklearn_json/classification.py b/sklearn_json/classification.py index d0cb36c..d12588a 100644 --- a/sklearn_json/classification.py +++ b/sklearn_json/classification.py @@ -306,39 +306,30 @@ def deserialize_tree(tree_dict, n_features, n_classes, n_outputs): def serialize_decision_tree(model): - tree, dtypes = serialize_tree(model.tree_) - serialized_model = { - 'meta': 'decision-tree', - 'feature_importances_': model.feature_importances_.tolist(), - 'max_features_': model.max_features_, - 'n_classes_': int(model.n_classes_), - 'n_features_': model.n_features_, - 'n_outputs_': model.n_outputs_, - 'tree_': tree, - 'classes_': model.classes_.tolist(), - 'params': model.get_params() - } - - - tree_dtypes = [] - for i in range(0, len(dtypes)): - tree_dtypes.append(dtypes[i].str) - - serialized_model['tree_']['nodes_dtype'] = tree_dtypes + # tree, dtypes = serialize_tree(model.tree_) + #print(model.feature_importances_) + serialized_model = {'meta': 'decision-tree'} + serialized_model.update({k: (v.tolist() if isinstance(v, np.ndarray) else int(v) if isinstance(v, np.int64) else v) for k, v in vars(model).items() }) + serialized_model['params'] = model.get_params() + if hasattr(model, "tree_"): + tree, dtypes = serialize_tree(model.tree_) + tree_dtypes = [] + for i in range(0, len(dtypes)): + tree_dtypes.append(dtypes[i].str) + serialized_model['tree_'] = {'nodes_dtype': tree_dtypes, **tree} return serialized_model def deserialize_decision_tree(model_dict): deserialized_model = DecisionTreeClassifier(**model_dict['params']) - deserialized_model.classes_ = np.array(model_dict['classes_']) deserialized_model.max_features_ = model_dict['max_features_'] deserialized_model.n_classes_ = model_dict['n_classes_'] - deserialized_model.n_features_ = model_dict['n_features_'] + deserialized_model.n_features_in_ = model_dict['n_features_in_'] deserialized_model.n_outputs_ = model_dict['n_outputs_'] - tree = deserialize_tree(model_dict['tree_'], model_dict['n_features_'], model_dict['n_classes_'], model_dict['n_outputs_']) + tree = deserialize_tree(model_dict['tree_'], model_dict['n_features_in_'], model_dict['n_classes_'], model_dict['n_outputs_']) deserialized_model.tree_ = tree return deserialized_model @@ -405,63 +396,40 @@ def deserialize_gradient_boosting(model_dict): def serialize_random_forest(model): - serialized_model = { - 'meta': 'rf', - 'max_depth': model.max_depth, - 'min_samples_split': model.min_samples_split, - 'min_samples_leaf': model.min_samples_leaf, - 'min_weight_fraction_leaf': model.min_weight_fraction_leaf, - 'max_features': model.max_features, - 'max_leaf_nodes': model.max_leaf_nodes, - 'min_impurity_decrease': model.min_impurity_decrease, - 'min_impurity_split': model.min_impurity_split, - 'n_features_': model.n_features_, - 'n_outputs_': model.n_outputs_, - 'classes_': model.classes_.tolist(), - 'estimators_': [serialize_decision_tree(decision_tree) for decision_tree in model.estimators_], - 'params': model.get_params() - } - - if 'oob_score_' in model.__dict__: - serialized_model['oob_score_'] = model.oob_score_ - if 'oob_decision_function_' in model.__dict__: - serialized_model['oob_decision_function_'] = model.oob_decision_function_.tolist() - - if isinstance(model.n_classes_, int): - serialized_model['n_classes_'] = model.n_classes_ - else: - serialized_model['n_classes_'] = model.n_classes_.tolist() + serialized_model = {"meta": "rf"} + serialized_model.update({k: (v.tolist() if isinstance(v, np.ndarray) else v) for k, v in vars(model).items()}) + serialized_model["params"] = model.get_params() + serialized_model.pop("estimator") + serialized_model.pop("estimator_") + #serialized_model['estimator'] = serialize_decision_tree(model.estimator) + #serialized_model['estimator_'] = serialized_model['estimator'].copy() + serialized_model['estimators_'] = [serialize_decision_tree(decision_tree) for decision_tree in model.estimators_] + + #if 'oob_score_' in model.__dict__: + # serialized_model['oob_score_'] = model.oob_score_ + #if 'oob_decision_function_' in model.__dict__: + # serialized_model['oob_decision_function_'] = model.oob_decision_function_.tolist() + + #if isinstance(model.n_classes_, int): + # serialized_model['n_classes_'] = model.n_classes_ + #else: + # serialized_model['n_classes_'] = model.n_classes_.tolist() return serialized_model def deserialize_random_forest(model_dict): - model = RandomForestClassifier(**model_dict['params']) + model = RandomForestClassifier(**model_dict["params"]) + attrs = [k for k in model_dict if k not in model_dict["params"]] + for attr in attrs: + if isinstance(model_dict[attr], list): + attr_val = np.array(model_dict[attr]) + else: + attr_val = model_dict[attr] + setattr(model, attr, attr_val) estimators = [deserialize_decision_tree(decision_tree) for decision_tree in model_dict['estimators_']] model.estimators_ = np.array(estimators) - model.classes_ = np.array(model_dict['classes_']) - model.n_features_ = model_dict['n_features_'] - model.n_outputs_ = model_dict['n_outputs_'] - model.max_depth = model_dict['max_depth'] - model.min_samples_split = model_dict['min_samples_split'] - model.min_samples_leaf = model_dict['min_samples_leaf'] - model.min_weight_fraction_leaf = model_dict['min_weight_fraction_leaf'] - model.max_features = model_dict['max_features'] - model.max_leaf_nodes = model_dict['max_leaf_nodes'] - model.min_impurity_decrease = model_dict['min_impurity_decrease'] - model.min_impurity_split = model_dict['min_impurity_split'] - - if 'oob_score_' in model_dict: - model.oob_score_ = model_dict['oob_score_'] - if 'oob_decision_function_' in model_dict: - model.oob_decision_function_ = model_dict['oob_decision_function_'] - - if isinstance(model_dict['n_classes_'], list): - model.n_classes_ = np.array(model_dict['n_classes_']) - else: - model.n_classes_ = model_dict['n_classes_'] - return model From 633ef1d1ede98a5ecb554783e31e61b46a09289c Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 21 Jun 2023 14:11:48 -0400 Subject: [PATCH 2/6] Format using black --- setup.py | 39 +-- sklearn_json/__init__.py | 67 ++-- sklearn_json/classification.py | 583 ++++++++++++++++++--------------- sklearn_json/csr.py | 22 +- sklearn_json/regression.py | 396 ++++++++++++---------- test/test_classification.py | 100 ++++-- test/test_regression.py | 26 +- 7 files changed, 697 insertions(+), 536 deletions(-) diff --git a/setup.py b/setup.py index ec0b7e3..dd77912 100644 --- a/setup.py +++ b/setup.py @@ -1,24 +1,25 @@ import setuptools + with open("README.md", "r") as fh: long_description = fh.read() setuptools.setup( - name='sklearn-json', - version='0.1.0', - author="Mathieu Rodrigue", - author_email="support@mlrequest.com", - description="A safe, transparent way to share and deploy scikit-learn models.", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/mlrequest/sklearn-json", - packages=setuptools.find_packages(), - install_requires=[ - 'scikit-learn>=0.21.3', - ], - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - ], - python_requires='>=3.5', - ) + name="sklearn-json", + version="0.1.0", + author="Mathieu Rodrigue", + author_email="support@mlrequest.com", + description="A safe, transparent way to share and deploy scikit-learn models.", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/mlrequest/sklearn-json", + packages=setuptools.find_packages(), + install_requires=[ + "scikit-learn>=0.21.3", + ], + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], + python_requires=">=3.5", +) diff --git a/sklearn_json/__init__.py b/sklearn_json/__init__.py index 50f6aa3..bb584a3 100644 --- a/sklearn_json/__init__.py +++ b/sklearn_json/__init__.py @@ -3,14 +3,20 @@ from sklearn import svm, discriminant_analysis, dummy from sklearn.linear_model import LogisticRegression, Perceptron from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor -from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, RandomForestRegressor, GradientBoostingRegressor, _gb_losses +from sklearn.ensemble import ( + RandomForestClassifier, + GradientBoostingClassifier, + RandomForestRegressor, + GradientBoostingRegressor, + _gb_losses, +) from sklearn.naive_bayes import BernoulliNB, GaussianNB, MultinomialNB, ComplementNB from sklearn.linear_model import LinearRegression, Lasso, Ridge from sklearn.neural_network import MLPClassifier, MLPRegressor from sklearn.svm import SVR import json -__version__ = '0.1.0' +__version__ = "0.1.0" def serialize_model(model): @@ -58,55 +64,59 @@ def serialize_model(model): elif isinstance(model, MLPRegressor): return reg.serialize_mlp_regressor(model) else: - raise ModellNotSupported('This model type is not currently supported. Email support@mlrequest.com to request a feature or report a bug.') + raise ModellNotSupported( + "This model type is not currently supported. Email support@mlrequest.com to request a feature or report a bug." + ) def deserialize_model(model_dict): - if model_dict['meta'] == 'lr': + if model_dict["meta"] == "lr": return clf.deserialize_logistic_regression(model_dict) - elif model_dict['meta'] == 'bernoulli-nb': + elif model_dict["meta"] == "bernoulli-nb": return clf.deserialize_bernoulli_nb(model_dict) - elif model_dict['meta'] == 'gaussian-nb': + elif model_dict["meta"] == "gaussian-nb": return clf.deserialize_gaussian_nb(model_dict) - elif model_dict['meta'] == 'multinomial-nb': + elif model_dict["meta"] == "multinomial-nb": return clf.deserialize_multinomial_nb(model_dict) - elif model_dict['meta'] == 'complement-nb': + elif model_dict["meta"] == "complement-nb": return clf.deserialize_complement_nb(model_dict) - elif model_dict['meta'] == 'lda': + elif model_dict["meta"] == "lda": return clf.deserialize_lda(model_dict) - elif model_dict['meta'] == 'qda': + elif model_dict["meta"] == "qda": return clf.deserialize_qda(model_dict) - elif model_dict['meta'] == 'svm': + elif model_dict["meta"] == "svm": return clf.deserialize_svm(model_dict) - elif model_dict['meta'] == 'perceptron': + elif model_dict["meta"] == "perceptron": return clf.deserialize_perceptron(model_dict) - elif model_dict['meta'] == 'decision-tree': + elif model_dict["meta"] == "decision-tree": return clf.deserialize_decision_tree(model_dict) - elif model_dict['meta'] == 'gb': + elif model_dict["meta"] == "gb": return clf.deserialize_gradient_boosting(model_dict) - elif model_dict['meta'] == 'rf': + elif model_dict["meta"] == "rf": return clf.deserialize_random_forest(model_dict) - elif model_dict['meta'] == 'mlp': + elif model_dict["meta"] == "mlp": return clf.deserialize_mlp(model_dict) - elif model_dict['meta'] == 'linear-regression': + elif model_dict["meta"] == "linear-regression": return reg.deserialize_linear_regressor(model_dict) - elif model_dict['meta'] == 'lasso-regression': + elif model_dict["meta"] == "lasso-regression": return reg.deserialize_lasso_regressor(model_dict) - elif model_dict['meta'] == 'ridge-regression': + elif model_dict["meta"] == "ridge-regression": return reg.deserialize_ridge_regressor(model_dict) - elif model_dict['meta'] == 'svr': + elif model_dict["meta"] == "svr": return reg.deserialize_svr(model_dict) - elif model_dict['meta'] == 'decision-tree-regression': + elif model_dict["meta"] == "decision-tree-regression": return reg.deserialize_decision_tree_regressor(model_dict) - elif model_dict['meta'] == 'gb-regression': + elif model_dict["meta"] == "gb-regression": return reg.deserialize_gradient_boosting_regressor(model_dict) - elif model_dict['meta'] == 'rf-regression': + elif model_dict["meta"] == "rf-regression": return reg.deserialize_random_forest_regressor(model_dict) - elif model_dict['meta'] == 'mlp-regression': + elif model_dict["meta"] == "mlp-regression": return reg.deserialize_mlp_regressor(model_dict) else: - raise ModellNotSupported('Model type not supported or corrupt JSON file. Email support@mlrequest.com to request a feature or report a bug.') + raise ModellNotSupported( + "Model type not supported or corrupt JSON file. Email support@mlrequest.com to request a feature or report a bug." + ) def to_dict(model): @@ -118,14 +128,15 @@ def from_dict(model_dict): def to_json(model, model_name): - with open(model_name, 'w') as model_json: + with open(model_name, "w") as model_json: json.dump(serialize_model(model), model_json) def from_json(model_name): - with open(model_name, 'r') as model_json: + with open(model_name, "r") as model_json: model_dict = json.load(model_json) return deserialize_model(model_dict) + class ModellNotSupported(Exception): - pass \ No newline at end of file + pass diff --git a/sklearn_json/classification.py b/sklearn_json/classification.py index d12588a..d089c42 100644 --- a/sklearn_json/classification.py +++ b/sklearn_json/classification.py @@ -4,7 +4,11 @@ from sklearn.linear_model import LogisticRegression, Perceptron from sklearn.tree import DecisionTreeClassifier from sklearn.tree._tree import Tree -from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, _gb_losses +from sklearn.ensemble import ( + RandomForestClassifier, + GradientBoostingClassifier, + _gb_losses, +) from sklearn.naive_bayes import BernoulliNB, GaussianNB, MultinomialNB, ComplementNB from sklearn.neural_network import MLPClassifier from sklearn.preprocessing import LabelBinarizer @@ -16,262 +20,276 @@ def serialize_logistic_regression(model): serialized_model = { - 'meta': 'lr', - 'classes_': model.classes_.tolist(), - 'coef_': model.coef_.tolist(), - 'intercept_': model.intercept_.tolist(), - 'n_iter_': model.n_iter_.tolist(), - 'params': model.get_params() + "meta": "lr", + "classes_": model.classes_.tolist(), + "coef_": model.coef_.tolist(), + "intercept_": model.intercept_.tolist(), + "n_iter_": model.n_iter_.tolist(), + "params": model.get_params(), } return serialized_model def deserialize_logistic_regression(model_dict): - model = LogisticRegression(model_dict['params']) + model = LogisticRegression(model_dict["params"]) - model.classes_ = np.array(model_dict['classes_']) - model.coef_ = np.array(model_dict['coef_']) - model.intercept_ = np.array(model_dict['intercept_']) - model.n_iter_ = np.array(model_dict['intercept_']) + model.classes_ = np.array(model_dict["classes_"]) + model.coef_ = np.array(model_dict["coef_"]) + model.intercept_ = np.array(model_dict["intercept_"]) + model.n_iter_ = np.array(model_dict["intercept_"]) return model def serialize_bernoulli_nb(model): serialized_model = { - 'meta': 'bernoulli-nb', - 'classes_': model.classes_.tolist(), - 'class_count_': model.class_count_.tolist(), - 'class_log_prior_': model.class_log_prior_.tolist(), - 'feature_count_': model.feature_count_.tolist(), - 'feature_log_prob_': model.feature_log_prob_.tolist(), - 'params': model.get_params() + "meta": "bernoulli-nb", + "classes_": model.classes_.tolist(), + "class_count_": model.class_count_.tolist(), + "class_log_prior_": model.class_log_prior_.tolist(), + "feature_count_": model.feature_count_.tolist(), + "feature_log_prob_": model.feature_log_prob_.tolist(), + "params": model.get_params(), } return serialized_model def deserialize_bernoulli_nb(model_dict): - model = BernoulliNB(model_dict['params']) + model = BernoulliNB(model_dict["params"]) - model.classes_ = np.array(model_dict['classes_']) - model.class_count_ = np.array(model_dict['class_count_']) - model.class_log_prior_ = np.array(model_dict['class_log_prior_']) - model.feature_count_= np.array(model_dict['feature_count_']) - model.feature_log_prob_ = np.array(model_dict['feature_log_prob_']) + model.classes_ = np.array(model_dict["classes_"]) + model.class_count_ = np.array(model_dict["class_count_"]) + model.class_log_prior_ = np.array(model_dict["class_log_prior_"]) + model.feature_count_ = np.array(model_dict["feature_count_"]) + model.feature_log_prob_ = np.array(model_dict["feature_log_prob_"]) return model def serialize_gaussian_nb(model): serialized_model = { - 'meta': 'gaussian-nb', - 'classes_': model.classes_.tolist(), - 'class_count_': model.class_count_.tolist(), - 'class_prior_': model.class_prior_.tolist(), - 'theta_': model.theta_.tolist(), - 'sigma_': model.sigma_.tolist(), - 'epsilon_': model.epsilon_, - 'params': model.get_params() + "meta": "gaussian-nb", + "classes_": model.classes_.tolist(), + "class_count_": model.class_count_.tolist(), + "class_prior_": model.class_prior_.tolist(), + "theta_": model.theta_.tolist(), + "sigma_": model.sigma_.tolist(), + "epsilon_": model.epsilon_, + "params": model.get_params(), } return serialized_model def deserialize_gaussian_nb(model_dict): - model = GaussianNB(model_dict['params']) + model = GaussianNB(model_dict["params"]) - model.classes_ = np.array(model_dict['classes_']) - model.class_count_ = np.array(model_dict['class_count_']) - model.class_prior_ = np.array(model_dict['class_prior_']) - model.theta_ = np.array(model_dict['theta_']) - model.sigma_ = np.array(model_dict['sigma_']) - model.epsilon_ = model_dict['epsilon_'] + model.classes_ = np.array(model_dict["classes_"]) + model.class_count_ = np.array(model_dict["class_count_"]) + model.class_prior_ = np.array(model_dict["class_prior_"]) + model.theta_ = np.array(model_dict["theta_"]) + model.sigma_ = np.array(model_dict["sigma_"]) + model.epsilon_ = model_dict["epsilon_"] return model def serialize_multinomial_nb(model): serialized_model = { - 'meta': 'multinomial-nb', - 'classes_': model.classes_.tolist(), - 'class_count_': model.class_count_.tolist(), - 'class_log_prior_': model.class_log_prior_.tolist(), - 'feature_count_': model.feature_count_.tolist(), - 'feature_log_prob_': model.feature_log_prob_.tolist(), - 'params': model.get_params() + "meta": "multinomial-nb", + "classes_": model.classes_.tolist(), + "class_count_": model.class_count_.tolist(), + "class_log_prior_": model.class_log_prior_.tolist(), + "feature_count_": model.feature_count_.tolist(), + "feature_log_prob_": model.feature_log_prob_.tolist(), + "params": model.get_params(), } return serialized_model def deserialize_multinomial_nb(model_dict): - model = MultinomialNB(model_dict['params']) + model = MultinomialNB(model_dict["params"]) - model.classes_ = np.array(model_dict['classes_']) - model.class_count_ = np.array(model_dict['class_count_']) - model.class_log_prior_ = np.array(model_dict['class_log_prior_']) - model.feature_count_= np.array(model_dict['feature_count_']) - model.feature_log_prob_ = np.array(model_dict['feature_log_prob_']) + model.classes_ = np.array(model_dict["classes_"]) + model.class_count_ = np.array(model_dict["class_count_"]) + model.class_log_prior_ = np.array(model_dict["class_log_prior_"]) + model.feature_count_ = np.array(model_dict["feature_count_"]) + model.feature_log_prob_ = np.array(model_dict["feature_log_prob_"]) return model def serialize_complement_nb(model): serialized_model = { - 'meta': 'complement-nb', - 'classes_': model.classes_.tolist(), - 'class_count_': model.class_count_.tolist(), - 'class_log_prior_': model.class_log_prior_.tolist(), - 'feature_count_': model.feature_count_.tolist(), - 'feature_log_prob_': model.feature_log_prob_.tolist(), - 'feature_all_': model.feature_all_.tolist(), - 'params': model.get_params() + "meta": "complement-nb", + "classes_": model.classes_.tolist(), + "class_count_": model.class_count_.tolist(), + "class_log_prior_": model.class_log_prior_.tolist(), + "feature_count_": model.feature_count_.tolist(), + "feature_log_prob_": model.feature_log_prob_.tolist(), + "feature_all_": model.feature_all_.tolist(), + "params": model.get_params(), } return serialized_model def deserialize_complement_nb(model_dict): - model = ComplementNB(model_dict['params']) + model = ComplementNB(model_dict["params"]) - model.classes_ = np.array(model_dict['classes_']) - model.class_count_ = np.array(model_dict['class_count_']) - model.class_log_prior_ = np.array(model_dict['class_log_prior_']) - model.feature_count_= np.array(model_dict['feature_count_']) - model.feature_log_prob_ = np.array(model_dict['feature_log_prob_']) - model.feature_all_ = np.array(model_dict['feature_all_']) + model.classes_ = np.array(model_dict["classes_"]) + model.class_count_ = np.array(model_dict["class_count_"]) + model.class_log_prior_ = np.array(model_dict["class_log_prior_"]) + model.feature_count_ = np.array(model_dict["feature_count_"]) + model.feature_log_prob_ = np.array(model_dict["feature_log_prob_"]) + model.feature_all_ = np.array(model_dict["feature_all_"]) return model def serialize_lda(model): serialized_model = { - 'meta': 'lda', - 'coef_': model.coef_.tolist(), - 'intercept_': model.intercept_.tolist(), - 'explained_variance_ratio_': model.explained_variance_ratio_.tolist(), - 'means_': model.means_.tolist(), - 'priors_': model.priors_.tolist(), - 'scalings_': model.scalings_.tolist(), - 'xbar_': model.xbar_.tolist(), - 'classes_': model.classes_.tolist(), - 'params': model.get_params() + "meta": "lda", + "coef_": model.coef_.tolist(), + "intercept_": model.intercept_.tolist(), + "explained_variance_ratio_": model.explained_variance_ratio_.tolist(), + "means_": model.means_.tolist(), + "priors_": model.priors_.tolist(), + "scalings_": model.scalings_.tolist(), + "xbar_": model.xbar_.tolist(), + "classes_": model.classes_.tolist(), + "params": model.get_params(), } - if 'covariance_' in model.__dict__: - serialized_model['covariance_'] = model.covariance_.tolist() + if "covariance_" in model.__dict__: + serialized_model["covariance_"] = model.covariance_.tolist() return serialized_model def deserialize_lda(model_dict): - model = discriminant_analysis.LinearDiscriminantAnalysis(**model_dict['params']) - - model.coef_ = np.array(model_dict['coef_']).astype(np.float64) - model.intercept_ = np.array(model_dict['intercept_']).astype(np.float64) - model.explained_variance_ratio_ = np.array(model_dict['explained_variance_ratio_']).astype(np.float64) - model.means_ = np.array(model_dict['means_']).astype(np.float64) - model.priors_ = np.array(model_dict['priors_']).astype(np.float64) - model.scalings_ = np.array(model_dict['scalings_']).astype(np.float64) - model.xbar_ = np.array(model_dict['xbar_']).astype(np.float64) - model.classes_ = np.array(model_dict['classes_']).astype(np.int64) + model = discriminant_analysis.LinearDiscriminantAnalysis(**model_dict["params"]) + + model.coef_ = np.array(model_dict["coef_"]).astype(np.float64) + model.intercept_ = np.array(model_dict["intercept_"]).astype(np.float64) + model.explained_variance_ratio_ = np.array( + model_dict["explained_variance_ratio_"] + ).astype(np.float64) + model.means_ = np.array(model_dict["means_"]).astype(np.float64) + model.priors_ = np.array(model_dict["priors_"]).astype(np.float64) + model.scalings_ = np.array(model_dict["scalings_"]).astype(np.float64) + model.xbar_ = np.array(model_dict["xbar_"]).astype(np.float64) + model.classes_ = np.array(model_dict["classes_"]).astype(np.int64) return model def serialize_qda(model): serialized_model = { - 'meta': 'qda', - 'means_': model.means_.tolist(), - 'priors_': model.priors_.tolist(), - 'scalings_': [array.tolist() for array in model.scalings_], - 'rotations_': [array.tolist() for array in model.rotations_], - 'classes_': model.classes_.tolist(), - 'params': model.get_params() + "meta": "qda", + "means_": model.means_.tolist(), + "priors_": model.priors_.tolist(), + "scalings_": [array.tolist() for array in model.scalings_], + "rotations_": [array.tolist() for array in model.rotations_], + "classes_": model.classes_.tolist(), + "params": model.get_params(), } - if 'covariance_' in model.__dict__: - serialized_model['covariance_'] = model.covariance_.tolist() + if "covariance_" in model.__dict__: + serialized_model["covariance_"] = model.covariance_.tolist() return serialized_model def deserialize_qda(model_dict): - model = discriminant_analysis.QuadraticDiscriminantAnalysis(**model_dict['params']) + model = discriminant_analysis.QuadraticDiscriminantAnalysis(**model_dict["params"]) - model.means_ = np.array(model_dict['means_']).astype(np.float64) - model.priors_ = np.array(model_dict['priors_']).astype(np.float64) - model.scalings_ = np.array(model_dict['scalings_']).astype(np.float64) - model.rotations_ = np.array(model_dict['rotations_']).astype(np.float64) - model.classes_ = np.array(model_dict['classes_']).astype(np.int64) + model.means_ = np.array(model_dict["means_"]).astype(np.float64) + model.priors_ = np.array(model_dict["priors_"]).astype(np.float64) + model.scalings_ = np.array(model_dict["scalings_"]).astype(np.float64) + model.rotations_ = np.array(model_dict["rotations_"]).astype(np.float64) + model.classes_ = np.array(model_dict["classes_"]).astype(np.int64) return model def serialize_svm(model): serialized_model = { - 'meta': 'svm', - 'class_weight_': model.class_weight_.tolist(), - 'classes_': model.classes_.tolist(), - 'support_': model.support_.tolist(), - 'n_support_': model.n_support_.tolist(), - 'intercept_': model.intercept_.tolist(), - 'probA_': model.probA_.tolist(), - 'probB_': model.probB_.tolist(), - '_intercept_': model._intercept_.tolist(), - 'shape_fit_': model.shape_fit_, - '_gamma': model._gamma, - 'params': model.get_params() + "meta": "svm", + "class_weight_": model.class_weight_.tolist(), + "classes_": model.classes_.tolist(), + "support_": model.support_.tolist(), + "n_support_": model.n_support_.tolist(), + "intercept_": model.intercept_.tolist(), + "probA_": model.probA_.tolist(), + "probB_": model.probB_.tolist(), + "_intercept_": model._intercept_.tolist(), + "shape_fit_": model.shape_fit_, + "_gamma": model._gamma, + "params": model.get_params(), } if isinstance(model.support_vectors_, sp.sparse.csr_matrix): - serialized_model['support_vectors_'] = csr.serialize_csr_matrix(model.support_vectors_) + serialized_model["support_vectors_"] = csr.serialize_csr_matrix( + model.support_vectors_ + ) elif isinstance(model.support_vectors_, np.ndarray): - serialized_model['support_vectors_'] = model.support_vectors_.tolist() + serialized_model["support_vectors_"] = model.support_vectors_.tolist() if isinstance(model.dual_coef_, sp.sparse.csr_matrix): - serialized_model['dual_coef_'] = csr.serialize_csr_matrix(model.dual_coef_) + serialized_model["dual_coef_"] = csr.serialize_csr_matrix(model.dual_coef_) elif isinstance(model.dual_coef_, np.ndarray): - serialized_model['dual_coef_'] = model.dual_coef_.tolist() + serialized_model["dual_coef_"] = model.dual_coef_.tolist() if isinstance(model._dual_coef_, sp.sparse.csr_matrix): - serialized_model['_dual_coef_'] = csr.serialize_csr_matrix(model._dual_coef_) + serialized_model["_dual_coef_"] = csr.serialize_csr_matrix(model._dual_coef_) elif isinstance(model._dual_coef_, np.ndarray): - serialized_model['_dual_coef_'] = model._dual_coef_.tolist() + serialized_model["_dual_coef_"] = model._dual_coef_.tolist() return serialized_model def deserialize_svm(model_dict): - model = svm.SVC(**model_dict['params']) - model.shape_fit_ = model_dict['shape_fit_'] - model._gamma = model_dict['_gamma'] - - model.class_weight_ = np.array(model_dict['class_weight_']).astype(np.float64) - model.classes_ = np.array(model_dict['classes_']) - model.support_ = np.array(model_dict['support_']).astype(np.int32) - model.n_support_ = np.array(model_dict['n_support_']).astype(np.int32) - model.intercept_ = np.array(model_dict['intercept_']).astype(np.float64) - model.probA_ = np.array(model_dict['probA_']).astype(np.float64) - model.probB_ = np.array(model_dict['probB_']).astype(np.float64) - model._intercept_ = np.array(model_dict['_intercept_']).astype(np.float64) - - if 'meta' in model_dict['support_vectors_'] and model_dict['support_vectors_']['meta'] == 'csr': - model.support_vectors_ = csr.deserialize_csr_matrix(model_dict['support_vectors_']) + model = svm.SVC(**model_dict["params"]) + model.shape_fit_ = model_dict["shape_fit_"] + model._gamma = model_dict["_gamma"] + + model.class_weight_ = np.array(model_dict["class_weight_"]).astype(np.float64) + model.classes_ = np.array(model_dict["classes_"]) + model.support_ = np.array(model_dict["support_"]).astype(np.int32) + model.n_support_ = np.array(model_dict["n_support_"]).astype(np.int32) + model.intercept_ = np.array(model_dict["intercept_"]).astype(np.float64) + model.probA_ = np.array(model_dict["probA_"]).astype(np.float64) + model.probB_ = np.array(model_dict["probB_"]).astype(np.float64) + model._intercept_ = np.array(model_dict["_intercept_"]).astype(np.float64) + + if ( + "meta" in model_dict["support_vectors_"] + and model_dict["support_vectors_"]["meta"] == "csr" + ): + model.support_vectors_ = csr.deserialize_csr_matrix( + model_dict["support_vectors_"] + ) model._sparse = True else: - model.support_vectors_ = np.array(model_dict['support_vectors_']).astype(np.float64) + model.support_vectors_ = np.array(model_dict["support_vectors_"]).astype( + np.float64 + ) model._sparse = False - if 'meta' in model_dict['dual_coef_'] and model_dict['dual_coef_']['meta'] == 'csr': - model.dual_coef_ = csr.deserialize_csr_matrix(model_dict['dual_coef_']) + if "meta" in model_dict["dual_coef_"] and model_dict["dual_coef_"]["meta"] == "csr": + model.dual_coef_ = csr.deserialize_csr_matrix(model_dict["dual_coef_"]) else: - model.dual_coef_ = np.array(model_dict['dual_coef_']).astype(np.float64) + model.dual_coef_ = np.array(model_dict["dual_coef_"]).astype(np.float64) - if 'meta' in model_dict['_dual_coef_'] and model_dict['_dual_coef_']['meta'] == 'csr': - model._dual_coef_ = csr.deserialize_csr_matrix(model_dict['_dual_coef_']) + if ( + "meta" in model_dict["_dual_coef_"] + and model_dict["_dual_coef_"]["meta"] == "csr" + ): + model._dual_coef_ = csr.deserialize_csr_matrix(model_dict["_dual_coef_"]) else: - model._dual_coef_ = np.array(model_dict['_dual_coef_']).astype(np.float64) + model._dual_coef_ = np.array(model_dict["_dual_coef_"]).astype(np.float64) return model @@ -285,19 +303,30 @@ def serialize_dummy_classifier(model): def serialize_tree(tree): serialized_tree = tree.__getstate__() - dtypes = serialized_tree['nodes'].dtype - serialized_tree['nodes'] = serialized_tree['nodes'].tolist() - serialized_tree['values'] = serialized_tree['values'].tolist() + dtypes = serialized_tree["nodes"].dtype + serialized_tree["nodes"] = serialized_tree["nodes"].tolist() + serialized_tree["values"] = serialized_tree["values"].tolist() return serialized_tree, dtypes def deserialize_tree(tree_dict, n_features, n_classes, n_outputs): - tree_dict['nodes'] = [tuple(lst) for lst in tree_dict['nodes']] - - names = ['left_child', 'right_child', 'feature', 'threshold', 'impurity', 'n_node_samples', 'weighted_n_node_samples'] - tree_dict['nodes'] = np.array(tree_dict['nodes'], dtype=np.dtype({'names': names, 'formats': tree_dict['nodes_dtype']})) - tree_dict['values'] = np.array(tree_dict['values']) + tree_dict["nodes"] = [tuple(lst) for lst in tree_dict["nodes"]] + + names = [ + "left_child", + "right_child", + "feature", + "threshold", + "impurity", + "n_node_samples", + "weighted_n_node_samples", + ] + tree_dict["nodes"] = np.array( + tree_dict["nodes"], + dtype=np.dtype({"names": names, "formats": tree_dict["nodes_dtype"]}), + ) + tree_dict["values"] = np.array(tree_dict["values"]) tree = Tree(n_features, np.array([n_classes], dtype=np.intp), n_outputs) tree.__setstate__(tree_dict) @@ -307,29 +336,45 @@ def deserialize_tree(tree_dict, n_features, n_classes, n_outputs): def serialize_decision_tree(model): # tree, dtypes = serialize_tree(model.tree_) - #print(model.feature_importances_) - serialized_model = {'meta': 'decision-tree'} - serialized_model.update({k: (v.tolist() if isinstance(v, np.ndarray) else int(v) if isinstance(v, np.int64) else v) for k, v in vars(model).items() }) - serialized_model['params'] = model.get_params() + # print(model.feature_importances_) + serialized_model = {"meta": "decision-tree"} + serialized_model.update( + { + k: ( + v.tolist() + if isinstance(v, np.ndarray) + else int(v) + if isinstance(v, np.int64) + else v + ) + for k, v in vars(model).items() + } + ) + serialized_model["params"] = model.get_params() if hasattr(model, "tree_"): tree, dtypes = serialize_tree(model.tree_) tree_dtypes = [] for i in range(0, len(dtypes)): tree_dtypes.append(dtypes[i].str) - serialized_model['tree_'] = {'nodes_dtype': tree_dtypes, **tree} + serialized_model["tree_"] = {"nodes_dtype": tree_dtypes, **tree} return serialized_model def deserialize_decision_tree(model_dict): - deserialized_model = DecisionTreeClassifier(**model_dict['params']) - deserialized_model.classes_ = np.array(model_dict['classes_']) - deserialized_model.max_features_ = model_dict['max_features_'] - deserialized_model.n_classes_ = model_dict['n_classes_'] - deserialized_model.n_features_in_ = model_dict['n_features_in_'] - deserialized_model.n_outputs_ = model_dict['n_outputs_'] - - tree = deserialize_tree(model_dict['tree_'], model_dict['n_features_in_'], model_dict['n_classes_'], model_dict['n_outputs_']) + deserialized_model = DecisionTreeClassifier(**model_dict["params"]) + deserialized_model.classes_ = np.array(model_dict["classes_"]) + deserialized_model.max_features_ = model_dict["max_features_"] + deserialized_model.n_classes_ = model_dict["n_classes_"] + deserialized_model.n_features_in_ = model_dict["n_features_in_"] + deserialized_model.n_outputs_ = model_dict["n_outputs_"] + + tree = deserialize_tree( + model_dict["tree_"], + model_dict["n_features_in_"], + model_dict["n_classes_"], + model_dict["n_outputs_"], + ) deserialized_model.tree_ = tree return deserialized_model @@ -337,82 +382,97 @@ def deserialize_decision_tree(model_dict): def serialize_gradient_boosting(model): serialized_model = { - 'meta': 'gb', - 'classes_': model.classes_.tolist(), - 'max_features_': model.max_features_, - 'n_classes_': model.n_classes_, - 'n_features_': model.n_features_, - 'train_score_': model.train_score_.tolist(), - 'params': model.get_params(), - 'estimators_shape': list(model.estimators_.shape), - 'estimators_': [] + "meta": "gb", + "classes_": model.classes_.tolist(), + "max_features_": model.max_features_, + "n_classes_": model.n_classes_, + "n_features_": model.n_features_, + "train_score_": model.train_score_.tolist(), + "params": model.get_params(), + "estimators_shape": list(model.estimators_.shape), + "estimators_": [], } - if isinstance(model.init_, dummy.DummyClassifier): - serialized_model['init_'] = serialize_dummy_classifier(model.init_) - serialized_model['init_']['meta'] = 'dummy' + if isinstance(model.init_, dummy.DummyClassifier): + serialized_model["init_"] = serialize_dummy_classifier(model.init_) + serialized_model["init_"]["meta"] = "dummy" elif isinstance(model.init_, str): - serialized_model['init_'] = model.init_ + serialized_model["init_"] = model.init_ if isinstance(model.loss_, _gb_losses.BinomialDeviance): - serialized_model['loss_'] = 'deviance' + serialized_model["loss_"] = "deviance" elif isinstance(model.loss_, _gb_losses.ExponentialLoss): - serialized_model['loss_'] = 'exponential' + serialized_model["loss_"] = "exponential" elif isinstance(model.loss_, _gb_losses.MultinomialDeviance): - serialized_model['loss_'] = 'multinomial' + serialized_model["loss_"] = "multinomial" - if 'priors' in model.init_.__dict__: - serialized_model['priors'] = model.init_.priors.tolist() + if "priors" in model.init_.__dict__: + serialized_model["priors"] = model.init_.priors.tolist() - serialized_model['estimators_'] = [regression.serialize_decision_tree_regressor(regression_tree) for regression_tree in model.estimators_.reshape(-1, )] + serialized_model["estimators_"] = [ + regression.serialize_decision_tree_regressor(regression_tree) + for regression_tree in model.estimators_.reshape( + -1, + ) + ] return serialized_model def deserialize_gradient_boosting(model_dict): - model = GradientBoostingClassifier(**model_dict['params']) - estimators = [regression.deserialize_decision_tree_regressor(tree) for tree in model_dict['estimators_']] - model.estimators_ = np.array(estimators).reshape(model_dict['estimators_shape']) - if 'init_' in model_dict and model_dict['init_']['meta'] == 'dummy': + model = GradientBoostingClassifier(**model_dict["params"]) + estimators = [ + regression.deserialize_decision_tree_regressor(tree) + for tree in model_dict["estimators_"] + ] + model.estimators_ = np.array(estimators).reshape(model_dict["estimators_shape"]) + if "init_" in model_dict and model_dict["init_"]["meta"] == "dummy": model.init_ = dummy.DummyClassifier() - model.init_.__dict__ = model_dict['init_'] - model.init_.__dict__.pop('meta') - - model.classes_ = np.array(model_dict['classes_']) - model.train_score_ = np.array(model_dict['train_score_']) - model.max_features_ = model_dict['max_features_'] - model.n_classes_ = model_dict['n_classes_'] - model.n_features_ = model_dict['n_features_'] - if model_dict['loss_'] == 'deviance': + model.init_.__dict__ = model_dict["init_"] + model.init_.__dict__.pop("meta") + + model.classes_ = np.array(model_dict["classes_"]) + model.train_score_ = np.array(model_dict["train_score_"]) + model.max_features_ = model_dict["max_features_"] + model.n_classes_ = model_dict["n_classes_"] + model.n_features_ = model_dict["n_features_"] + if model_dict["loss_"] == "deviance": model.loss_ = _gb_losses.BinomialDeviance(model.n_classes_) - elif model_dict['loss_'] == 'exponential': + elif model_dict["loss_"] == "exponential": model.loss_ = _gb_losses.ExponentialLoss(model.n_classes_) - elif model_dict['loss_'] == 'multinomial': + elif model_dict["loss_"] == "multinomial": model.loss_ = _gb_losses.MultinomialDeviance(model.n_classes_) - if 'priors' in model_dict: - model.init_.priors = np.array(model_dict['priors']) + if "priors" in model_dict: + model.init_.priors = np.array(model_dict["priors"]) return model def serialize_random_forest(model): serialized_model = {"meta": "rf"} - serialized_model.update({k: (v.tolist() if isinstance(v, np.ndarray) else v) for k, v in vars(model).items()}) + serialized_model.update( + { + k: (v.tolist() if isinstance(v, np.ndarray) else v) + for k, v in vars(model).items() + } + ) serialized_model["params"] = model.get_params() serialized_model.pop("estimator") serialized_model.pop("estimator_") - #serialized_model['estimator'] = serialize_decision_tree(model.estimator) - #serialized_model['estimator_'] = serialized_model['estimator'].copy() - serialized_model['estimators_'] = [serialize_decision_tree(decision_tree) for decision_tree in model.estimators_] + # serialized_model['estimator'] = serialize_decision_tree(model.estimator) + # serialized_model['estimator_'] = serialized_model['estimator'].copy() + serialized_model["estimators_"] = [ + serialize_decision_tree(decision_tree) for decision_tree in model.estimators_ + ] - #if 'oob_score_' in model.__dict__: + # if 'oob_score_' in model.__dict__: # serialized_model['oob_score_'] = model.oob_score_ - #if 'oob_decision_function_' in model.__dict__: + # if 'oob_decision_function_' in model.__dict__: # serialized_model['oob_decision_function_'] = model.oob_decision_function_.tolist() - #if isinstance(model.n_classes_, int): + # if isinstance(model.n_classes_, int): # serialized_model['n_classes_'] = model.n_classes_ - #else: + # else: # serialized_model['n_classes_'] = model.n_classes_.tolist() return serialized_model @@ -427,7 +487,10 @@ def deserialize_random_forest(model_dict): else: attr_val = model_dict[attr] setattr(model, attr, attr_val) - estimators = [deserialize_decision_tree(decision_tree) for decision_tree in model_dict['estimators_']] + estimators = [ + deserialize_decision_tree(decision_tree) + for decision_tree in model_dict["estimators_"] + ] model.estimators_ = np.array(estimators) return model @@ -435,38 +498,38 @@ def deserialize_random_forest(model_dict): def serialize_perceptron(model): serialized_model = { - 'meta': 'perceptron', - 'coef_': model.coef_.tolist(), - 'intercept_': model.intercept_.tolist(), - 'n_iter_': model.n_iter_, - 'classes_': model.classes_.tolist(), - 'params': model.get_params() + "meta": "perceptron", + "coef_": model.coef_.tolist(), + "intercept_": model.intercept_.tolist(), + "n_iter_": model.n_iter_, + "classes_": model.classes_.tolist(), + "params": model.get_params(), } - if 'covariance_' in model.__dict__: - serialized_model['covariance_'] = model.covariance_.tolist() + if "covariance_" in model.__dict__: + serialized_model["covariance_"] = model.covariance_.tolist() return serialized_model def deserialize_perceptron(model_dict): - model = Perceptron(**model_dict['params']) + model = Perceptron(**model_dict["params"]) - model.coef_ = np.array(model_dict['coef_']).astype(np.float64) - model.intercept_ = np.array(model_dict['intercept_']).astype(np.float64) - model.n_iter_ = np.array(model_dict['n_iter_']).astype(np.float64) - model.classes_ = np.array(model_dict['classes_']).astype(np.int64) + model.coef_ = np.array(model_dict["coef_"]).astype(np.float64) + model.intercept_ = np.array(model_dict["intercept_"]).astype(np.float64) + model.n_iter_ = np.array(model_dict["n_iter_"]).astype(np.float64) + model.classes_ = np.array(model_dict["classes_"]).astype(np.int64) return model def serialize_label_binarizer(label_binarizer): serialized_label_binarizer = { - 'neg_label': label_binarizer.neg_label, - 'pos_label': label_binarizer.pos_label, - 'sparse_output': label_binarizer.sparse_output, - 'y_type_': label_binarizer.y_type_, - 'sparse_input_': label_binarizer.sparse_input_, - 'classes_': label_binarizer.classes_.tolist() + "neg_label": label_binarizer.neg_label, + "pos_label": label_binarizer.pos_label, + "sparse_output": label_binarizer.sparse_output, + "y_type_": label_binarizer.y_type_, + "sparse_input_": label_binarizer.sparse_input_, + "classes_": label_binarizer.classes_.tolist(), } return serialized_label_binarizer @@ -474,50 +537,50 @@ def serialize_label_binarizer(label_binarizer): def deserialize_label_binarizer(label_binarizer_dict): label_binarizer = LabelBinarizer() - label_binarizer.neg_label = label_binarizer_dict['neg_label'] - label_binarizer.pos_label = label_binarizer_dict['pos_label'] - label_binarizer.sparse_output = label_binarizer_dict['sparse_output'] - label_binarizer.y_type_ = label_binarizer_dict['y_type_'] - label_binarizer.sparse_input_ = label_binarizer_dict['sparse_input_'] - label_binarizer.classes_ = np.array(label_binarizer_dict['classes_']) + label_binarizer.neg_label = label_binarizer_dict["neg_label"] + label_binarizer.pos_label = label_binarizer_dict["pos_label"] + label_binarizer.sparse_output = label_binarizer_dict["sparse_output"] + label_binarizer.y_type_ = label_binarizer_dict["y_type_"] + label_binarizer.sparse_input_ = label_binarizer_dict["sparse_input_"] + label_binarizer.classes_ = np.array(label_binarizer_dict["classes_"]) return label_binarizer def serialize_mlp(model): serialized_model = { - 'meta': 'mlp', - 'coefs_': [array.tolist() for array in model.coefs_], - 'loss_': model.loss_, - 'intercepts_': [array.tolist() for array in model.intercepts_], - 'n_iter_': model.n_iter_, - 'n_layers_': model.n_layers_, - 'n_outputs_': model.n_outputs_, - 'out_activation_': model.out_activation_, - '_label_binarizer': serialize_label_binarizer(model._label_binarizer), - 'params': model.get_params() + "meta": "mlp", + "coefs_": [array.tolist() for array in model.coefs_], + "loss_": model.loss_, + "intercepts_": [array.tolist() for array in model.intercepts_], + "n_iter_": model.n_iter_, + "n_layers_": model.n_layers_, + "n_outputs_": model.n_outputs_, + "out_activation_": model.out_activation_, + "_label_binarizer": serialize_label_binarizer(model._label_binarizer), + "params": model.get_params(), } if isinstance(model.classes_, list): - serialized_model['classes_'] = [array.tolist() for array in model.classes_] + serialized_model["classes_"] = [array.tolist() for array in model.classes_] else: - serialized_model['classes_'] = model.classes_.tolist() + serialized_model["classes_"] = model.classes_.tolist() return serialized_model def deserialize_mlp(model_dict): - model = MLPClassifier(**model_dict['params']) - - model.coefs_ = np.array(model_dict['coefs_']) - model.loss_ = model_dict['loss_'] - model.intercepts_ = np.array(model_dict['intercepts_']) - model.n_iter_ = model_dict['n_iter_'] - model.n_layers_ = model_dict['n_layers_'] - model.n_outputs_ = model_dict['n_outputs_'] - model.out_activation_ = model_dict['out_activation_'] - model._label_binarizer = deserialize_label_binarizer(model_dict['_label_binarizer']) - - model.classes_ = np.array(model_dict['classes_']) + model = MLPClassifier(**model_dict["params"]) + + model.coefs_ = np.array(model_dict["coefs_"]) + model.loss_ = model_dict["loss_"] + model.intercepts_ = np.array(model_dict["intercepts_"]) + model.n_iter_ = model_dict["n_iter_"] + model.n_layers_ = model_dict["n_layers_"] + model.n_outputs_ = model_dict["n_outputs_"] + model.out_activation_ = model_dict["out_activation_"] + model._label_binarizer = deserialize_label_binarizer(model_dict["_label_binarizer"]) + + model.classes_ = np.array(model_dict["classes_"]) return model diff --git a/sklearn_json/csr.py b/sklearn_json/csr.py index df2690c..5e299ec 100644 --- a/sklearn_json/csr.py +++ b/sklearn_json/csr.py @@ -4,19 +4,21 @@ def serialize_csr_matrix(csr_matrix): serialized_csr_matrix = { - 'meta': 'csr', - 'data': csr_matrix.data.tolist(), - 'indices': csr_matrix.indices.tolist(), - 'indptr': csr_matrix.indptr.tolist(), - '_shape': csr_matrix._shape, + "meta": "csr", + "data": csr_matrix.data.tolist(), + "indices": csr_matrix.indices.tolist(), + "indptr": csr_matrix.indptr.tolist(), + "_shape": csr_matrix._shape, } return serialized_csr_matrix -def deserialize_csr_matrix(csr_dict, data_type=np.float64, indices_type=np.int32, indptr_type=np.int32): - csr_matrix = sp.sparse.csr_matrix(tuple(csr_dict['_shape'])) - csr_matrix.data = np.array(csr_dict['data']).astype(data_type) - csr_matrix.indices = np.array(csr_dict['indices']).astype(indices_type) - csr_matrix.indptr = np.array(csr_dict['indptr']).astype(indptr_type) +def deserialize_csr_matrix( + csr_dict, data_type=np.float64, indices_type=np.int32, indptr_type=np.int32 +): + csr_matrix = sp.sparse.csr_matrix(tuple(csr_dict["_shape"])) + csr_matrix.data = np.array(csr_dict["data"]).astype(data_type) + csr_matrix.indices = np.array(csr_dict["indices"]).astype(indices_type) + csr_matrix.indptr = np.array(csr_dict["indptr"]).astype(indptr_type) return csr_matrix diff --git a/sklearn_json/regression.py b/sklearn_json/regression.py index 208e44f..d3859b7 100644 --- a/sklearn_json/regression.py +++ b/sklearn_json/regression.py @@ -1,6 +1,10 @@ from sklearn.linear_model import LinearRegression, Lasso, Ridge from sklearn.tree import DecisionTreeRegressor -from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor, _gb_losses +from sklearn.ensemble import ( + RandomForestRegressor, + GradientBoostingRegressor, + _gb_losses, +) from sklearn.neural_network import MLPRegressor from sklearn.tree._tree import Tree from sklearn.svm import SVR @@ -12,158 +16,170 @@ def serialize_linear_regressor(model): serialized_model = { - 'meta': 'linear-regression', - 'coef_': model.coef_.tolist(), - 'intercept_': model.intercept_.tolist(), - 'params': model.get_params() + "meta": "linear-regression", + "coef_": model.coef_.tolist(), + "intercept_": model.intercept_.tolist(), + "params": model.get_params(), } return serialized_model def deserialize_linear_regressor(model_dict): - model = LinearRegression(model_dict['params']) + model = LinearRegression(model_dict["params"]) - model.coef_ = np.array(model_dict['coef_']) - model.intercept_ = np.array(model_dict['intercept_']) + model.coef_ = np.array(model_dict["coef_"]) + model.intercept_ = np.array(model_dict["intercept_"]) return model def serialize_lasso_regressor(model): serialized_model = { - 'meta': 'lasso-regression', - 'coef_': model.coef_.tolist(), - 'params': model.get_params() + "meta": "lasso-regression", + "coef_": model.coef_.tolist(), + "params": model.get_params(), } if isinstance(model.n_iter_, int): - serialized_model['n_iter_'] = model.n_iter_ + serialized_model["n_iter_"] = model.n_iter_ else: - serialized_model['n_iter_'] = model.n_iter_.tolist() + serialized_model["n_iter_"] = model.n_iter_.tolist() if isinstance(model.n_iter_, float): - serialized_model['intercept_'] = model.intercept_ + serialized_model["intercept_"] = model.intercept_ else: - serialized_model['intercept_'] = model.intercept_.tolist() + serialized_model["intercept_"] = model.intercept_.tolist() return serialized_model def deserialize_lasso_regressor(model_dict): - model = Lasso(model_dict['params']) + model = Lasso(model_dict["params"]) - model.coef_ = np.array(model_dict['coef_']) + model.coef_ = np.array(model_dict["coef_"]) - if isinstance(model_dict['n_iter_'], list): - model.n_iter_ = np.array(model_dict['n_iter_']) + if isinstance(model_dict["n_iter_"], list): + model.n_iter_ = np.array(model_dict["n_iter_"]) else: - model.n_iter_ = int(model_dict['n_iter_']) + model.n_iter_ = int(model_dict["n_iter_"]) - if isinstance(model_dict['intercept_'], list): - model.intercept_ = np.array(model_dict['intercept_']) + if isinstance(model_dict["intercept_"], list): + model.intercept_ = np.array(model_dict["intercept_"]) else: - model.intercept_ = float(model_dict['intercept_']) + model.intercept_ = float(model_dict["intercept_"]) return model def serialize_ridge_regressor(model): serialized_model = { - 'meta': 'ridge-regression', - 'coef_': model.coef_.tolist(), - 'params': model.get_params() + "meta": "ridge-regression", + "coef_": model.coef_.tolist(), + "params": model.get_params(), } if model.n_iter_: - serialized_model['n_iter_'] = model.n_iter_.tolist() + serialized_model["n_iter_"] = model.n_iter_.tolist() if isinstance(model.n_iter_, float): - serialized_model['intercept_'] = model.intercept_ + serialized_model["intercept_"] = model.intercept_ else: - serialized_model['intercept_'] = model.intercept_.tolist() + serialized_model["intercept_"] = model.intercept_.tolist() return serialized_model def deserialize_ridge_regressor(model_dict): - model = Ridge(model_dict['params']) + model = Ridge(model_dict["params"]) - model.coef_ = np.array(model_dict['coef_']) + model.coef_ = np.array(model_dict["coef_"]) - if 'n_iter_' in model_dict: - model.n_iter_ = np.array(model_dict['n_iter_']) + if "n_iter_" in model_dict: + model.n_iter_ = np.array(model_dict["n_iter_"]) - if isinstance(model_dict['intercept_'], list): - model.intercept_ = np.array(model_dict['intercept_']) + if isinstance(model_dict["intercept_"], list): + model.intercept_ = np.array(model_dict["intercept_"]) else: - model.intercept_ = float(model_dict['intercept_']) + model.intercept_ = float(model_dict["intercept_"]) return model def serialize_svr(model): serialized_model = { - 'meta': 'svr', - 'class_weight_': model.class_weight_.tolist(), - 'support_': model.support_.tolist(), - 'n_support_': model.n_support_.tolist(), - 'intercept_': model.intercept_.tolist(), - 'probA_': model.probA_.tolist(), - 'probB_': model.probB_.tolist(), - '_intercept_': model._intercept_.tolist(), - 'shape_fit_': model.shape_fit_, - '_gamma': model._gamma, - 'params': model.get_params() + "meta": "svr", + "class_weight_": model.class_weight_.tolist(), + "support_": model.support_.tolist(), + "n_support_": model.n_support_.tolist(), + "intercept_": model.intercept_.tolist(), + "probA_": model.probA_.tolist(), + "probB_": model.probB_.tolist(), + "_intercept_": model._intercept_.tolist(), + "shape_fit_": model.shape_fit_, + "_gamma": model._gamma, + "params": model.get_params(), } if isinstance(model.support_vectors_, sp.sparse.csr_matrix): - serialized_model['support_vectors_'] = csr.serialize_csr_matrix(model.support_vectors_) + serialized_model["support_vectors_"] = csr.serialize_csr_matrix( + model.support_vectors_ + ) elif isinstance(model.support_vectors_, np.ndarray): - serialized_model['support_vectors_'] = model.support_vectors_.tolist() + serialized_model["support_vectors_"] = model.support_vectors_.tolist() if isinstance(model.dual_coef_, sp.sparse.csr_matrix): - serialized_model['dual_coef_'] = csr.serialize_csr_matrix(model.dual_coef_) + serialized_model["dual_coef_"] = csr.serialize_csr_matrix(model.dual_coef_) elif isinstance(model.dual_coef_, np.ndarray): - serialized_model['dual_coef_'] = model.dual_coef_.tolist() + serialized_model["dual_coef_"] = model.dual_coef_.tolist() if isinstance(model._dual_coef_, sp.sparse.csr_matrix): - serialized_model['_dual_coef_'] = csr.serialize_csr_matrix(model._dual_coef_) + serialized_model["_dual_coef_"] = csr.serialize_csr_matrix(model._dual_coef_) elif isinstance(model._dual_coef_, np.ndarray): - serialized_model['_dual_coef_'] = model._dual_coef_.tolist() + serialized_model["_dual_coef_"] = model._dual_coef_.tolist() return serialized_model def deserialize_svr(model_dict): - model = SVR(**model_dict['params']) - model.shape_fit_ = model_dict['shape_fit_'] - model._gamma = model_dict['_gamma'] - - model.class_weight_ = np.array(model_dict['class_weight_']).astype(np.float64) - model.support_ = np.array(model_dict['support_']).astype(np.int32) - model.n_support_ = np.array(model_dict['n_support_']).astype(np.int32) - model.intercept_ = np.array(model_dict['intercept_']).astype(np.float64) - model.probA_ = np.array(model_dict['probA_']).astype(np.float64) - model.probB_ = np.array(model_dict['probB_']).astype(np.float64) - model._intercept_ = np.array(model_dict['_intercept_']).astype(np.float64) - - if 'meta' in model_dict['support_vectors_'] and model_dict['support_vectors_']['meta'] == 'csr': - model.support_vectors_ = csr.deserialize_csr_matrix(model_dict['support_vectors_']) + model = SVR(**model_dict["params"]) + model.shape_fit_ = model_dict["shape_fit_"] + model._gamma = model_dict["_gamma"] + + model.class_weight_ = np.array(model_dict["class_weight_"]).astype(np.float64) + model.support_ = np.array(model_dict["support_"]).astype(np.int32) + model.n_support_ = np.array(model_dict["n_support_"]).astype(np.int32) + model.intercept_ = np.array(model_dict["intercept_"]).astype(np.float64) + model.probA_ = np.array(model_dict["probA_"]).astype(np.float64) + model.probB_ = np.array(model_dict["probB_"]).astype(np.float64) + model._intercept_ = np.array(model_dict["_intercept_"]).astype(np.float64) + + if ( + "meta" in model_dict["support_vectors_"] + and model_dict["support_vectors_"]["meta"] == "csr" + ): + model.support_vectors_ = csr.deserialize_csr_matrix( + model_dict["support_vectors_"] + ) model._sparse = True else: - model.support_vectors_ = np.array(model_dict['support_vectors_']).astype(np.float64) + model.support_vectors_ = np.array(model_dict["support_vectors_"]).astype( + np.float64 + ) model._sparse = False - if 'meta' in model_dict['dual_coef_'] and model_dict['dual_coef_']['meta'] == 'csr': - model.dual_coef_ = csr.deserialize_csr_matrix(model_dict['dual_coef_']) + if "meta" in model_dict["dual_coef_"] and model_dict["dual_coef_"]["meta"] == "csr": + model.dual_coef_ = csr.deserialize_csr_matrix(model_dict["dual_coef_"]) else: - model.dual_coef_ = np.array(model_dict['dual_coef_']).astype(np.float64) + model.dual_coef_ = np.array(model_dict["dual_coef_"]).astype(np.float64) - if 'meta' in model_dict['_dual_coef_'] and model_dict['_dual_coef_']['meta'] == 'csr': - model._dual_coef_ = csr.deserialize_csr_matrix(model_dict['_dual_coef_']) + if ( + "meta" in model_dict["_dual_coef_"] + and model_dict["_dual_coef_"]["meta"] == "csr" + ): + model._dual_coef_ = csr.deserialize_csr_matrix(model_dict["_dual_coef_"]) else: - model._dual_coef_ = np.array(model_dict['_dual_coef_']).astype(np.float64) + model._dual_coef_ = np.array(model_dict["_dual_coef_"]).astype(np.float64) return model @@ -171,19 +187,30 @@ def deserialize_svr(model_dict): def serialize_tree(tree): serialized_tree = tree.__getstate__() # serialized_tree['nodes_dtype'] = serialized_tree['nodes'].dtype - dtypes = serialized_tree['nodes'].dtype - serialized_tree['nodes'] = serialized_tree['nodes'].tolist() - serialized_tree['values'] = serialized_tree['values'].tolist() + dtypes = serialized_tree["nodes"].dtype + serialized_tree["nodes"] = serialized_tree["nodes"].tolist() + serialized_tree["values"] = serialized_tree["values"].tolist() return serialized_tree, dtypes def deserialize_tree(tree_dict, n_features, n_classes, n_outputs): - tree_dict['nodes'] = [tuple(lst) for lst in tree_dict['nodes']] - - names = ['left_child', 'right_child', 'feature', 'threshold', 'impurity', 'n_node_samples', 'weighted_n_node_samples'] - tree_dict['nodes'] = np.array(tree_dict['nodes'], dtype=np.dtype({'names': names, 'formats': tree_dict['nodes_dtype']})) - tree_dict['values'] = np.array(tree_dict['values']) + tree_dict["nodes"] = [tuple(lst) for lst in tree_dict["nodes"]] + + names = [ + "left_child", + "right_child", + "feature", + "threshold", + "impurity", + "n_node_samples", + "weighted_n_node_samples", + ] + tree_dict["nodes"] = np.array( + tree_dict["nodes"], + dtype=np.dtype({"names": names, "formats": tree_dict["nodes_dtype"]}), + ) + tree_dict["values"] = np.array(tree_dict["values"]) tree = Tree(n_features, np.array([n_classes], dtype=np.intp), n_outputs) tree.__setstate__(tree_dict) @@ -194,12 +221,12 @@ def deserialize_tree(tree_dict, n_features, n_classes, n_outputs): def serialize_decision_tree_regressor(model): tree, dtypes = serialize_tree(model.tree_) serialized_model = { - 'meta': 'decision-tree-regression', - 'feature_importances_': model.feature_importances_.tolist(), - 'max_features_': model.max_features_, - 'n_features_': model.n_features_, - 'n_outputs_': model.n_outputs_, - 'tree_': tree + "meta": "decision-tree-regression", + "feature_importances_": model.feature_importances_.tolist(), + "max_features_": model.max_features_, + "n_features_": model.n_features_, + "n_outputs_": model.n_outputs_, + "tree_": tree, } # serialized_model. @@ -208,7 +235,7 @@ def serialize_decision_tree_regressor(model): for i in range(0, len(dtypes)): tree_dtypes.append(dtypes[i].str) - serialized_model['tree_']['nodes_dtype'] = tree_dtypes + serialized_model["tree_"]["nodes_dtype"] = tree_dtypes return serialized_model @@ -216,11 +243,13 @@ def serialize_decision_tree_regressor(model): def deserialize_decision_tree_regressor(model_dict): deserialized_decision_tree = DecisionTreeRegressor() - deserialized_decision_tree.max_features_ = model_dict['max_features_'] - deserialized_decision_tree.n_features_ = model_dict['n_features_'] - deserialized_decision_tree.n_outputs_ = model_dict['n_outputs_'] + deserialized_decision_tree.max_features_ = model_dict["max_features_"] + deserialized_decision_tree.n_features_ = model_dict["n_features_"] + deserialized_decision_tree.n_outputs_ = model_dict["n_outputs_"] - tree = deserialize_tree(model_dict['tree_'], model_dict['n_features_'], 1, model_dict['n_outputs_']) + tree = deserialize_tree( + model_dict["tree_"], model_dict["n_features_"], 1, model_dict["n_outputs_"] + ) deserialized_decision_tree.tree_ = tree return deserialized_decision_tree @@ -232,142 +261,147 @@ def serialize_dummy_regressor(model): def serialize_gradient_boosting_regressor(model): - serialized_model = { - 'meta': 'gb-regression', - 'max_features_': model.max_features_, - 'n_features_': model.n_features_, - 'train_score_': model.train_score_.tolist(), - 'params': model.get_params(), - 'estimators_shape': list(model.estimators_.shape), - 'estimators_': [] + "meta": "gb-regression", + "max_features_": model.max_features_, + "n_features_": model.n_features_, + "train_score_": model.train_score_.tolist(), + "params": model.get_params(), + "estimators_shape": list(model.estimators_.shape), + "estimators_": [], } - if isinstance(model.init_, dummy.DummyRegressor): - serialized_model['init_'] = serialize_dummy_regressor(model.init_) - serialized_model['init_']['meta'] = 'dummy' + if isinstance(model.init_, dummy.DummyRegressor): + serialized_model["init_"] = serialize_dummy_regressor(model.init_) + serialized_model["init_"]["meta"] = "dummy" elif isinstance(model.init_, str): - serialized_model['init_'] = model.init_ + serialized_model["init_"] = model.init_ if isinstance(model.loss_, _gb_losses.LeastSquaresError): - serialized_model['loss_'] = 'ls' + serialized_model["loss_"] = "ls" elif isinstance(model.loss_, _gb_losses.LeastAbsoluteError): - serialized_model['loss_'] = 'lad' + serialized_model["loss_"] = "lad" elif isinstance(model.loss_, _gb_losses.HuberLossFunction): - serialized_model['loss_'] = 'huber' + serialized_model["loss_"] = "huber" elif isinstance(model.loss_, _gb_losses.QuantileLossFunction): - serialized_model['loss_'] = 'quantile' + serialized_model["loss_"] = "quantile" - if 'priors' in model.init_.__dict__: - serialized_model['priors'] = model.init_.priors.tolist() + if "priors" in model.init_.__dict__: + serialized_model["priors"] = model.init_.priors.tolist() for tree in model.estimators_.reshape((-1,)): - serialized_model['estimators_'].append(serialize_decision_tree_regressor(tree)) + serialized_model["estimators_"].append(serialize_decision_tree_regressor(tree)) return serialized_model def deserialize_gradient_boosting_regressor(model_dict): - model = GradientBoostingRegressor(**model_dict['params']) - trees = [deserialize_decision_tree_regressor(tree) for tree in model_dict['estimators_']] - model.estimators_ = np.array(trees).reshape(model_dict['estimators_shape']) - if 'init_' in model_dict and model_dict['init_']['meta'] == 'dummy': + model = GradientBoostingRegressor(**model_dict["params"]) + trees = [ + deserialize_decision_tree_regressor(tree) for tree in model_dict["estimators_"] + ] + model.estimators_ = np.array(trees).reshape(model_dict["estimators_shape"]) + if "init_" in model_dict and model_dict["init_"]["meta"] == "dummy": model.init_ = dummy.DummyRegressor() - model.init_.__dict__ = model_dict['init_'] - model.init_.__dict__.pop('meta') + model.init_.__dict__ = model_dict["init_"] + model.init_.__dict__.pop("meta") - - model.train_score_ = np.array(model_dict['train_score_']) - model.max_features_ = model_dict['max_features_'] - model.n_features_ = model_dict['n_features_'] - if model_dict['loss_'] == 'ls': + model.train_score_ = np.array(model_dict["train_score_"]) + model.max_features_ = model_dict["max_features_"] + model.n_features_ = model_dict["n_features_"] + if model_dict["loss_"] == "ls": model.loss_ = _gb_losses.LeastSquaresError(1) - elif model_dict['loss_'] == 'lad': + elif model_dict["loss_"] == "lad": model.loss_ = _gb_losses.LeastAbsoluteError(1) - elif model_dict['loss_'] == 'huber': + elif model_dict["loss_"] == "huber": model.loss_ = _gb_losses.HuberLossFunction(1) - elif model_dict['loss_'] == 'quantile': + elif model_dict["loss_"] == "quantile": model.loss_ = _gb_losses.QuantileLossFunction(1) - if 'priors' in model_dict: - model.init_.priors = np.array(model_dict['priors']) + if "priors" in model_dict: + model.init_.priors = np.array(model_dict["priors"]) return model def serialize_random_forest_regressor(model): - serialized_model = { - 'meta': 'rf-regression', - 'max_depth': model.max_depth, - 'min_samples_split': model.min_samples_split, - 'min_samples_leaf': model.min_samples_leaf, - 'min_weight_fraction_leaf': model.min_weight_fraction_leaf, - 'max_features': model.max_features, - 'max_leaf_nodes': model.max_leaf_nodes, - 'min_impurity_decrease': model.min_impurity_decrease, - 'min_impurity_split': model.min_impurity_split, - 'n_features_': model.n_features_, - 'n_outputs_': model.n_outputs_, - 'estimators_': [serialize_decision_tree_regressor(decision_tree) for decision_tree in model.estimators_], - 'params': model.get_params() + "meta": "rf-regression", + "max_depth": model.max_depth, + "min_samples_split": model.min_samples_split, + "min_samples_leaf": model.min_samples_leaf, + "min_weight_fraction_leaf": model.min_weight_fraction_leaf, + "max_features": model.max_features, + "max_leaf_nodes": model.max_leaf_nodes, + "min_impurity_decrease": model.min_impurity_decrease, + "min_impurity_split": model.min_impurity_split, + "n_features_": model.n_features_, + "n_outputs_": model.n_outputs_, + "estimators_": [ + serialize_decision_tree_regressor(decision_tree) + for decision_tree in model.estimators_ + ], + "params": model.get_params(), } - if 'oob_score_' in model.__dict__: - serialized_model['oob_score_'] = model.oob_score_ - if 'oob_decision_function_' in model.__dict__: - serialized_model['oob_prediction_'] = model.oob_prediction_.tolist() + if "oob_score_" in model.__dict__: + serialized_model["oob_score_"] = model.oob_score_ + if "oob_decision_function_" in model.__dict__: + serialized_model["oob_prediction_"] = model.oob_prediction_.tolist() return serialized_model def deserialize_random_forest_regressor(model_dict): - model = RandomForestRegressor(**model_dict['params']) - estimators = [deserialize_decision_tree_regressor(decision_tree) for decision_tree in model_dict['estimators_']] + model = RandomForestRegressor(**model_dict["params"]) + estimators = [ + deserialize_decision_tree_regressor(decision_tree) + for decision_tree in model_dict["estimators_"] + ] model.estimators_ = np.array(estimators) - model.n_features_ = model_dict['n_features_'] - model.n_outputs_ = model_dict['n_outputs_'] - model.max_depth = model_dict['max_depth'] - model.min_samples_split = model_dict['min_samples_split'] - model.min_samples_leaf = model_dict['min_samples_leaf'] - model.min_weight_fraction_leaf = model_dict['min_weight_fraction_leaf'] - model.max_features = model_dict['max_features'] - model.max_leaf_nodes = model_dict['max_leaf_nodes'] - model.min_impurity_decrease = model_dict['min_impurity_decrease'] - model.min_impurity_split = model_dict['min_impurity_split'] - - if 'oob_score_' in model_dict: - model.oob_score_ = model_dict['oob_score_'] - if 'oob_prediction_' in model_dict: - model.oob_prediction_ =np.array(model_dict['oob_prediction_']) + model.n_features_ = model_dict["n_features_"] + model.n_outputs_ = model_dict["n_outputs_"] + model.max_depth = model_dict["max_depth"] + model.min_samples_split = model_dict["min_samples_split"] + model.min_samples_leaf = model_dict["min_samples_leaf"] + model.min_weight_fraction_leaf = model_dict["min_weight_fraction_leaf"] + model.max_features = model_dict["max_features"] + model.max_leaf_nodes = model_dict["max_leaf_nodes"] + model.min_impurity_decrease = model_dict["min_impurity_decrease"] + model.min_impurity_split = model_dict["min_impurity_split"] + + if "oob_score_" in model_dict: + model.oob_score_ = model_dict["oob_score_"] + if "oob_prediction_" in model_dict: + model.oob_prediction_ = np.array(model_dict["oob_prediction_"]) return model def serialize_mlp_regressor(model): serialized_model = { - 'meta': 'mlp-regression', - 'coefs_': model.coefs_, - 'loss_': model.loss_, - 'intercepts_': model.intercepts_, - 'n_iter_': model.n_iter_, - 'n_layers_': model.n_layers_, - 'n_outputs_': model.n_outputs_, - 'out_activation_': model.out_activation_, - 'params': model.get_params() + "meta": "mlp-regression", + "coefs_": model.coefs_, + "loss_": model.loss_, + "intercepts_": model.intercepts_, + "n_iter_": model.n_iter_, + "n_layers_": model.n_layers_, + "n_outputs_": model.n_outputs_, + "out_activation_": model.out_activation_, + "params": model.get_params(), } return serialized_model def deserialize_mlp_regressor(model_dict): - model = MLPRegressor(**model_dict['params']) - - model.coefs_ = model_dict['coefs_'] - model.loss_ = model_dict['loss_'] - model.intercepts_ = model_dict['intercepts_'] - model.n_iter_ = model_dict['n_iter_'] - model.n_layers_ = model_dict['n_layers_'] - model.n_outputs_ = model_dict['n_outputs_'] - model.out_activation_ = model_dict['out_activation_'] + model = MLPRegressor(**model_dict["params"]) + + model.coefs_ = model_dict["coefs_"] + model.loss_ = model_dict["loss_"] + model.intercepts_ = model_dict["intercepts_"] + model.n_iter_ = model_dict["n_iter_"] + model.n_layers_ = model_dict["n_layers_"] + model.n_outputs_ = model_dict["n_outputs_"] + model.out_activation_ = model_dict["out_activation_"] return model diff --git a/test/test_classification.py b/test/test_classification.py index da7dd63..3dd9634 100644 --- a/test/test_classification.py +++ b/test/test_classification.py @@ -14,14 +14,27 @@ class TestAPI(unittest.TestCase): - def setUp(self): - self.X, self.y = make_classification(n_samples=50, n_features=3, n_classes=3, n_informative=3, n_redundant=0, random_state=0, shuffle=False) + self.X, self.y = make_classification( + n_samples=50, + n_features=3, + n_classes=3, + n_informative=3, + n_redundant=0, + random_state=0, + shuffle=False, + ) feature_hasher = FeatureHasher(n_features=3) features = [] for i in range(0, 100): - features.append({'a': random.randint(0, 2), 'b': random.randint(3, 5), 'c': random.randint(6, 8)}) + features.append( + { + "a": random.randint(0, 2), + "b": random.randint(3, 5), + "c": random.randint(6, 8), + } + ) self.y_sparse = [random.randint(0, 2) for i in range(0, 100)] self.X_sparse = feature_hasher.transform(features) @@ -97,14 +110,14 @@ def test_bernoulli_nb(self): self.check_model(BernoulliNB()) self.check_sparse_model(BernoulliNB()) - model_name = 'bernoulli-nb.json' + model_name = "bernoulli-nb.json" self.check_model_json(BernoulliNB(), model_name) self.check_sparse_model_json(BernoulliNB(), model_name) def test_guassian_nb(self): self.check_model(GaussianNB()) - model_name = 'gaussian-nb.json' + model_name = "gaussian-nb.json" self.check_model_json(GaussianNB(), model_name) # No sklearn implementation for sparse matrix @@ -113,14 +126,14 @@ def test_multinomial_nb(self): self.check_model(MultinomialNB(), abs=True) self.check_sparse_model(MultinomialNB(), abs=True) - model_name = 'multinomial-nb.json' + model_name = "multinomial-nb.json" self.check_model_json(MultinomialNB(), model_name, abs=True) self.check_sparse_model_json(MultinomialNB(), model_name, abs=True) def test_complement_nb(self): self.check_model(ComplementNB(), abs=True) - model_name = 'complement-nb.json' + model_name = "complement-nb.json" self.check_model_json(ComplementNB(), model_name, abs=True) # No sklearn implementation for sparse matrix @@ -129,31 +142,35 @@ def test_logistic_regression(self): self.check_model(LogisticRegression()) self.check_sparse_model(LogisticRegression()) - model_name = 'lr.json' + model_name = "lr.json" self.check_model_json(LogisticRegression(), model_name) self.check_sparse_model_json(LogisticRegression(), model_name) def test_lda(self): self.check_model(discriminant_analysis.LinearDiscriminantAnalysis()) - model_name = 'lda.json' - self.check_model_json(discriminant_analysis.LinearDiscriminantAnalysis(), model_name) + model_name = "lda.json" + self.check_model_json( + discriminant_analysis.LinearDiscriminantAnalysis(), model_name + ) # No sklearn implementation for sparse matrix def test_qda(self): self.check_model(discriminant_analysis.QuadraticDiscriminantAnalysis()) - model_name = 'qda.json' - self.check_model_json(discriminant_analysis.QuadraticDiscriminantAnalysis(), model_name) + model_name = "qda.json" + self.check_model_json( + discriminant_analysis.QuadraticDiscriminantAnalysis(), model_name + ) # No sklearn implementation for sparse matrix def test_svm(self): - self.check_model(svm.SVC(gamma=0.001, C=100., kernel='linear')) - self.check_sparse_model(svm.SVC(gamma=0.001, C=100., kernel='linear')) + self.check_model(svm.SVC(gamma=0.001, C=100.0, kernel="linear")) + self.check_sparse_model(svm.SVC(gamma=0.001, C=100.0, kernel="linear")) - model_name = 'svm.json' + model_name = "svm.json" self.check_model_json(svm.SVC(), model_name) self.check_sparse_model_json(svm.SVC(), model_name) @@ -161,23 +178,29 @@ def test_decision_tree(self): self.check_model(DecisionTreeClassifier()) self.check_sparse_model(DecisionTreeClassifier()) - model_name = 'dt.json' + model_name = "dt.json" self.check_model_json(DecisionTreeClassifier(), model_name) self.check_sparse_model_json(DecisionTreeClassifier(), model_name) def test_gradient_boosting(self): self.check_model(GradientBoostingClassifier(n_estimators=25, learning_rate=1.0)) - self.check_sparse_model(GradientBoostingClassifier(n_estimators=25, learning_rate=1.0)) + self.check_sparse_model( + GradientBoostingClassifier(n_estimators=25, learning_rate=1.0) + ) - model_name = 'gb.json' + model_name = "gb.json" self.check_model_json(GradientBoostingClassifier(), model_name) self.check_sparse_model_json(GradientBoostingClassifier(), model_name) def test_random_forest(self): - self.check_model(RandomForestClassifier(n_estimators=10, max_depth=5, random_state=0)) - self.check_sparse_model(RandomForestClassifier(n_estimators=10, max_depth=5, random_state=0)) - - model_name = 'rf.json' + self.check_model( + RandomForestClassifier(n_estimators=10, max_depth=5, random_state=0) + ) + self.check_sparse_model( + RandomForestClassifier(n_estimators=10, max_depth=5, random_state=0) + ) + + model_name = "rf.json" self.check_model_json(RandomForestClassifier(), model_name) self.check_sparse_model_json(RandomForestClassifier(), model_name) @@ -185,15 +208,32 @@ def test_perceptron(self): self.check_model(Perceptron()) self.check_sparse_model(Perceptron()) - model_name = 'perceptron.json' + model_name = "perceptron.json" self.check_model_json(Perceptron(), model_name) self.check_sparse_model_json(Perceptron(), model_name) def test_mlp(self): - self.check_model(MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1)) - self.check_sparse_model(MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1)) - - model_name = 'mlp.json' - self.check_model_json(MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1), model_name) - self.check_sparse_model_json(MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1), model_name) - + self.check_model( + MLPClassifier( + solver="lbfgs", alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1 + ) + ) + self.check_sparse_model( + MLPClassifier( + solver="lbfgs", alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1 + ) + ) + + model_name = "mlp.json" + self.check_model_json( + MLPClassifier( + solver="lbfgs", alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1 + ), + model_name, + ) + self.check_sparse_model_json( + MLPClassifier( + solver="lbfgs", alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1 + ), + model_name, + ) diff --git a/test/test_regression.py b/test/test_regression.py index adf6f96..973f068 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -12,14 +12,21 @@ class TestAPI(unittest.TestCase): - def setUp(self): - self.X, self.y = make_regression(n_samples=50, n_features=3, n_informative=3, random_state=0, shuffle=False) + self.X, self.y = make_regression( + n_samples=50, n_features=3, n_informative=3, random_state=0, shuffle=False + ) feature_hasher = FeatureHasher(n_features=3) features = [] for i in range(0, 100): - features.append({'a': random.randint(0, 2), 'b': random.randint(3, 5), 'c': random.randint(6, 8)}) + features.append( + { + "a": random.randint(0, 2), + "b": random.randint(3, 5), + "c": random.randint(6, 8), + } + ) self.y_sparse = [random.random() for i in range(0, 100)] self.X_sparse = feature_hasher.transform(features) @@ -64,8 +71,8 @@ def test_ridge_regression(self): self.check_sparse_model(Ridge(alpha=0.5)) def test_svr(self): - self.check_model(SVR(gamma='scale', C=1.0, epsilon=0.2)) - self.check_sparse_model(SVR(gamma='scale', C=1.0, epsilon=0.2)) + self.check_model(SVR(gamma="scale", C=1.0, epsilon=0.2)) + self.check_sparse_model(SVR(gamma="scale", C=1.0, epsilon=0.2)) def test_decision_tree_regression(self): self.check_model(DecisionTreeRegressor()) @@ -76,10 +83,13 @@ def test_gradient_boosting_regression(self): self.check_sparse_model(GradientBoostingRegressor()) def test_random_forest_regression(self): - self.check_model(RandomForestRegressor(max_depth=2, random_state=0, n_estimators=100)) - self.check_sparse_model(RandomForestRegressor(max_depth=2, random_state=0, n_estimators=100)) + self.check_model( + RandomForestRegressor(max_depth=2, random_state=0, n_estimators=100) + ) + self.check_sparse_model( + RandomForestRegressor(max_depth=2, random_state=0, n_estimators=100) + ) def test_mlp_regression(self): self.check_model(MLPRegressor()) self.check_sparse_model(MLPRegressor()) - From ecd6c133324ba17c122a6b56777c8a800f96804c Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 21 Jun 2023 14:20:30 -0400 Subject: [PATCH 3/6] Update more formatting --- .gitignore | 1 - pyproject.toml | 2 +- sklearn_json/__init__.py | 36 ++++++++++++++++++---------------- sklearn_json/classification.py | 28 +++++++------------------- sklearn_json/regression.py | 15 +++++++------- test/test_classification.py | 20 ++++++++++--------- test/test_regression.py | 14 +++++++------ 7 files changed, 54 insertions(+), 62 deletions(-) diff --git a/.gitignore b/.gitignore index 9630ec3..cbdffd8 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,3 @@ build/ dist/ sklearn_json.egg-info/ .ignore/* - diff --git a/pyproject.toml b/pyproject.toml index 61e5fea..caa6e56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.ruff] # Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. Add isort select = ["E", "F", "I", "D"] -ignore = [] +ignore = ["D100", "D101", "D102", "D103", "D104"] # Allow autofix for all enabled rules (when `--fix`) is provided. fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"] diff --git a/sklearn_json/__init__.py b/sklearn_json/__init__.py index bb584a3..bdd452d 100644 --- a/sklearn_json/__init__.py +++ b/sklearn_json/__init__.py @@ -1,20 +1,26 @@ -from sklearn_json import classification as clf -from sklearn_json import regression as reg -from sklearn import svm, discriminant_analysis, dummy -from sklearn.linear_model import LogisticRegression, Perceptron -from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor +import json + +from sklearn import discriminant_analysis, svm from sklearn.ensemble import ( - RandomForestClassifier, GradientBoostingClassifier, - RandomForestRegressor, GradientBoostingRegressor, - _gb_losses, + RandomForestClassifier, + RandomForestRegressor, +) +from sklearn.linear_model import ( + Lasso, + LinearRegression, + LogisticRegression, + Perceptron, + Ridge, ) -from sklearn.naive_bayes import BernoulliNB, GaussianNB, MultinomialNB, ComplementNB -from sklearn.linear_model import LinearRegression, Lasso, Ridge +from sklearn.naive_bayes import BernoulliNB, ComplementNB, GaussianNB, MultinomialNB from sklearn.neural_network import MLPClassifier, MLPRegressor from sklearn.svm import SVR -import json +from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor + +from sklearn_json import classification as clf +from sklearn_json import regression as reg __version__ = "0.1.0" @@ -64,9 +70,7 @@ def serialize_model(model): elif isinstance(model, MLPRegressor): return reg.serialize_mlp_regressor(model) else: - raise ModellNotSupported( - "This model type is not currently supported. Email support@mlrequest.com to request a feature or report a bug." - ) + raise ModellNotSupported("This model type is not currently supported.") def deserialize_model(model_dict): @@ -114,9 +118,7 @@ def deserialize_model(model_dict): elif model_dict["meta"] == "mlp-regression": return reg.deserialize_mlp_regressor(model_dict) else: - raise ModellNotSupported( - "Model type not supported or corrupt JSON file. Email support@mlrequest.com to request a feature or report a bug." - ) + raise ModellNotSupported("Model type not supported or corrupt JSON file.") def to_dict(model): diff --git a/sklearn_json/classification.py b/sklearn_json/classification.py index d089c42..d831e9e 100644 --- a/sklearn_json/classification.py +++ b/sklearn_json/classification.py @@ -1,21 +1,19 @@ import numpy as np import scipy as sp -from sklearn import svm, discriminant_analysis, dummy -from sklearn.linear_model import LogisticRegression, Perceptron -from sklearn.tree import DecisionTreeClassifier -from sklearn.tree._tree import Tree +from sklearn import discriminant_analysis, dummy, svm from sklearn.ensemble import ( - RandomForestClassifier, GradientBoostingClassifier, + RandomForestClassifier, _gb_losses, ) -from sklearn.naive_bayes import BernoulliNB, GaussianNB, MultinomialNB, ComplementNB +from sklearn.linear_model import LogisticRegression, Perceptron +from sklearn.naive_bayes import BernoulliNB, ComplementNB, GaussianNB, MultinomialNB from sklearn.neural_network import MLPClassifier from sklearn.preprocessing import LabelBinarizer -from sklearn_json import regression -from sklearn_json import csr +from sklearn.tree import DecisionTreeClassifier +from sklearn.tree._tree import Tree -import json +from sklearn_json import csr, regression def serialize_logistic_regression(model): @@ -459,22 +457,10 @@ def serialize_random_forest(model): serialized_model["params"] = model.get_params() serialized_model.pop("estimator") serialized_model.pop("estimator_") - # serialized_model['estimator'] = serialize_decision_tree(model.estimator) - # serialized_model['estimator_'] = serialized_model['estimator'].copy() serialized_model["estimators_"] = [ serialize_decision_tree(decision_tree) for decision_tree in model.estimators_ ] - # if 'oob_score_' in model.__dict__: - # serialized_model['oob_score_'] = model.oob_score_ - # if 'oob_decision_function_' in model.__dict__: - # serialized_model['oob_decision_function_'] = model.oob_decision_function_.tolist() - - # if isinstance(model.n_classes_, int): - # serialized_model['n_classes_'] = model.n_classes_ - # else: - # serialized_model['n_classes_'] = model.n_classes_.tolist() - return serialized_model diff --git a/sklearn_json/regression.py b/sklearn_json/regression.py index d3859b7..770a74c 100644 --- a/sklearn_json/regression.py +++ b/sklearn_json/regression.py @@ -1,17 +1,18 @@ -from sklearn.linear_model import LinearRegression, Lasso, Ridge -from sklearn.tree import DecisionTreeRegressor +import numpy as np +import scipy as sp +from sklearn import dummy from sklearn.ensemble import ( - RandomForestRegressor, GradientBoostingRegressor, + RandomForestRegressor, _gb_losses, ) +from sklearn.linear_model import Lasso, LinearRegression, Ridge from sklearn.neural_network import MLPRegressor -from sklearn.tree._tree import Tree from sklearn.svm import SVR -from sklearn import dummy +from sklearn.tree import DecisionTreeRegressor +from sklearn.tree._tree import Tree + from sklearn_json import csr -import numpy as np -import scipy as sp def serialize_linear_regressor(model): diff --git a/test/test_classification.py b/test/test_classification.py index 3dd9634..c2e4cd7 100644 --- a/test/test_classification.py +++ b/test/test_classification.py @@ -1,15 +1,17 @@ +import random +import unittest + +import numpy as np +from numpy import testing +from sklearn import discriminant_analysis, svm from sklearn.datasets import make_classification +from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier from sklearn.feature_extraction import FeatureHasher -from sklearn import svm, discriminant_analysis from sklearn.linear_model import LogisticRegression, Perceptron -from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier -from sklearn.naive_bayes import BernoulliNB, GaussianNB, MultinomialNB, ComplementNB +from sklearn.naive_bayes import BernoulliNB, ComplementNB, GaussianNB, MultinomialNB from sklearn.neural_network import MLPClassifier from sklearn.tree import DecisionTreeClassifier -import unittest -import random -import numpy as np -from numpy import testing + import sklearn_json as skljson @@ -80,7 +82,7 @@ def check_model_json(self, model, model_name, abs=False): model.fit(self.X, self.y) # When - serialized_model = skljson.to_json(model, model_name) + skljson.to_json(model, model_name) deserialized_model = skljson.from_json(model_name) # Then @@ -97,7 +99,7 @@ def check_sparse_model_json(self, model, model_name, abs=False): model.fit(self.X_sparse, self.y_sparse) # When - serialized_model = skljson.to_json(model, model_name) + skljson.to_json(model, model_name) deserialized_model = skljson.from_json(model_name) # Then diff --git a/test/test_regression.py b/test/test_regression.py index 973f068..9698680 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -1,13 +1,15 @@ +import random +import unittest + +from numpy import testing from sklearn.datasets import make_regression +from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor from sklearn.feature_extraction import FeatureHasher -from sklearn.linear_model import LinearRegression, Lasso, Ridge -from sklearn.tree import DecisionTreeRegressor -from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor +from sklearn.linear_model import Lasso, LinearRegression, Ridge from sklearn.neural_network import MLPRegressor from sklearn.svm import SVR -from numpy import testing -import random -import unittest +from sklearn.tree import DecisionTreeRegressor + import sklearn_json as skljson From 5d3e64e74b3f2cb7aa446a945740c5f2f50fee3a Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 21 Jun 2023 16:02:34 -0400 Subject: [PATCH 4/6] Fix classification models --- .gitignore | 1 + sklearn_json/classification.py | 36 +++++++-------- sklearn_json/regression.py | 14 +++--- test/test_classification.py | 84 +++++++++++++++++----------------- 4 files changed, 66 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index cbdffd8..a5d9c85 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ build/ dist/ sklearn_json.egg-info/ .ignore/* +test.* diff --git a/sklearn_json/classification.py b/sklearn_json/classification.py index d831e9e..b6b93fc 100644 --- a/sklearn_json/classification.py +++ b/sklearn_json/classification.py @@ -30,7 +30,7 @@ def serialize_logistic_regression(model): def deserialize_logistic_regression(model_dict): - model = LogisticRegression(model_dict["params"]) + model = LogisticRegression(**model_dict["params"]) model.classes_ = np.array(model_dict["classes_"]) model.coef_ = np.array(model_dict["coef_"]) @@ -55,7 +55,7 @@ def serialize_bernoulli_nb(model): def deserialize_bernoulli_nb(model_dict): - model = BernoulliNB(model_dict["params"]) + model = BernoulliNB(**model_dict["params"]) model.classes_ = np.array(model_dict["classes_"]) model.class_count_ = np.array(model_dict["class_count_"]) @@ -73,7 +73,7 @@ def serialize_gaussian_nb(model): "class_count_": model.class_count_.tolist(), "class_prior_": model.class_prior_.tolist(), "theta_": model.theta_.tolist(), - "sigma_": model.sigma_.tolist(), + "var_": model.var_.tolist(), "epsilon_": model.epsilon_, "params": model.get_params(), } @@ -82,13 +82,13 @@ def serialize_gaussian_nb(model): def deserialize_gaussian_nb(model_dict): - model = GaussianNB(model_dict["params"]) + model = GaussianNB(**model_dict["params"]) model.classes_ = np.array(model_dict["classes_"]) model.class_count_ = np.array(model_dict["class_count_"]) model.class_prior_ = np.array(model_dict["class_prior_"]) model.theta_ = np.array(model_dict["theta_"]) - model.sigma_ = np.array(model_dict["sigma_"]) + model.var_ = np.array(model_dict["var_"]) model.epsilon_ = model_dict["epsilon_"] return model @@ -109,7 +109,7 @@ def serialize_multinomial_nb(model): def deserialize_multinomial_nb(model_dict): - model = MultinomialNB(model_dict["params"]) + model = MultinomialNB(**model_dict["params"]) model.classes_ = np.array(model_dict["classes_"]) model.class_count_ = np.array(model_dict["class_count_"]) @@ -136,7 +136,7 @@ def serialize_complement_nb(model): def deserialize_complement_nb(model_dict): - model = ComplementNB(model_dict["params"]) + model = ComplementNB(**model_dict["params"]) model.classes_ = np.array(model_dict["classes_"]) model.class_count_ = np.array(model_dict["class_count_"]) @@ -256,10 +256,10 @@ def deserialize_svm(model_dict): model.class_weight_ = np.array(model_dict["class_weight_"]).astype(np.float64) model.classes_ = np.array(model_dict["classes_"]) model.support_ = np.array(model_dict["support_"]).astype(np.int32) - model.n_support_ = np.array(model_dict["n_support_"]).astype(np.int32) + model._n_support = np.array(model_dict["n_support_"]).astype(np.int32) model.intercept_ = np.array(model_dict["intercept_"]).astype(np.float64) - model.probA_ = np.array(model_dict["probA_"]).astype(np.float64) - model.probB_ = np.array(model_dict["probB_"]).astype(np.float64) + model._probA = np.array(model_dict["probA_"]).astype(np.float64) + model._probB = np.array(model_dict["probB_"]).astype(np.float64) model._intercept_ = np.array(model_dict["_intercept_"]).astype(np.float64) if ( @@ -333,8 +333,6 @@ def deserialize_tree(tree_dict, n_features, n_classes, n_outputs): def serialize_decision_tree(model): - # tree, dtypes = serialize_tree(model.tree_) - # print(model.feature_importances_) serialized_model = {"meta": "decision-tree"} serialized_model.update( { @@ -384,7 +382,7 @@ def serialize_gradient_boosting(model): "classes_": model.classes_.tolist(), "max_features_": model.max_features_, "n_classes_": model.n_classes_, - "n_features_": model.n_features_, + "n_features_in_": model.n_features_in_, "train_score_": model.train_score_.tolist(), "params": model.get_params(), "estimators_shape": list(model.estimators_.shape), @@ -433,13 +431,13 @@ def deserialize_gradient_boosting(model_dict): model.train_score_ = np.array(model_dict["train_score_"]) model.max_features_ = model_dict["max_features_"] model.n_classes_ = model_dict["n_classes_"] - model.n_features_ = model_dict["n_features_"] + model.n_features_in_ = model_dict["n_features_in_"] if model_dict["loss_"] == "deviance": - model.loss_ = _gb_losses.BinomialDeviance(model.n_classes_) + model._loss = _gb_losses.BinomialDeviance(model.n_classes_) elif model_dict["loss_"] == "exponential": - model.loss_ = _gb_losses.ExponentialLoss(model.n_classes_) + model._loss = _gb_losses.ExponentialLoss(model.n_classes_) elif model_dict["loss_"] == "multinomial": - model.loss_ = _gb_losses.MultinomialDeviance(model.n_classes_) + model._loss = _gb_losses.MultinomialDeviance(model.n_classes_) if "priors" in model_dict: model.init_.priors = np.array(model_dict["priors"]) @@ -558,9 +556,9 @@ def serialize_mlp(model): def deserialize_mlp(model_dict): model = MLPClassifier(**model_dict["params"]) - model.coefs_ = np.array(model_dict["coefs_"]) + model.coefs_ = [np.array(x) for x in model_dict["coefs_"]] model.loss_ = model_dict["loss_"] - model.intercepts_ = np.array(model_dict["intercepts_"]) + model.intercepts_ = [np.array(x) for x in model_dict["intercepts_"]] model.n_iter_ = model_dict["n_iter_"] model.n_layers_ = model_dict["n_layers_"] model.n_outputs_ = model_dict["n_outputs_"] diff --git a/sklearn_json/regression.py b/sklearn_json/regression.py index 770a74c..4c0abc7 100644 --- a/sklearn_json/regression.py +++ b/sklearn_json/regression.py @@ -225,7 +225,7 @@ def serialize_decision_tree_regressor(model): "meta": "decision-tree-regression", "feature_importances_": model.feature_importances_.tolist(), "max_features_": model.max_features_, - "n_features_": model.n_features_, + "n_features_in_": model.n_features_in_, "n_outputs_": model.n_outputs_, "tree_": tree, } @@ -245,11 +245,11 @@ def deserialize_decision_tree_regressor(model_dict): deserialized_decision_tree = DecisionTreeRegressor() deserialized_decision_tree.max_features_ = model_dict["max_features_"] - deserialized_decision_tree.n_features_ = model_dict["n_features_"] + deserialized_decision_tree.n_features_in_ = model_dict["n_features_in_"] deserialized_decision_tree.n_outputs_ = model_dict["n_outputs_"] tree = deserialize_tree( - model_dict["tree_"], model_dict["n_features_"], 1, model_dict["n_outputs_"] + model_dict["tree_"], model_dict["n_features_in_"], 1, model_dict["n_outputs_"] ) deserialized_decision_tree.tree_ = tree @@ -265,7 +265,7 @@ def serialize_gradient_boosting_regressor(model): serialized_model = { "meta": "gb-regression", "max_features_": model.max_features_, - "n_features_": model.n_features_, + "n_features_in_": model.n_features_in_, "train_score_": model.train_score_.tolist(), "params": model.get_params(), "estimators_shape": list(model.estimators_.shape), @@ -308,7 +308,7 @@ def deserialize_gradient_boosting_regressor(model_dict): model.train_score_ = np.array(model_dict["train_score_"]) model.max_features_ = model_dict["max_features_"] - model.n_features_ = model_dict["n_features_"] + model.n_features_in_ = model_dict["n_features_in_"] if model_dict["loss_"] == "ls": model.loss_ = _gb_losses.LeastSquaresError(1) elif model_dict["loss_"] == "lad": @@ -334,7 +334,7 @@ def serialize_random_forest_regressor(model): "max_leaf_nodes": model.max_leaf_nodes, "min_impurity_decrease": model.min_impurity_decrease, "min_impurity_split": model.min_impurity_split, - "n_features_": model.n_features_, + "n_features_in_": model.n_features_in_, "n_outputs_": model.n_outputs_, "estimators_": [ serialize_decision_tree_regressor(decision_tree) @@ -359,7 +359,7 @@ def deserialize_random_forest_regressor(model_dict): ] model.estimators_ = np.array(estimators) - model.n_features_ = model_dict["n_features_"] + model.n_features_in_ = model_dict["n_features_in_"] model.n_outputs_ = model_dict["n_outputs_"] model.max_depth = model_dict["max_depth"] model.min_samples_split = model_dict["min_samples_split"] diff --git a/test/test_classification.py b/test/test_classification.py index c2e4cd7..63ca7f0 100644 --- a/test/test_classification.py +++ b/test/test_classification.py @@ -1,5 +1,4 @@ import random -import unittest import numpy as np from numpy import testing @@ -14,97 +13,96 @@ import sklearn_json as skljson - -class TestAPI(unittest.TestCase): - def setUp(self): - self.X, self.y = make_classification( - n_samples=50, - n_features=3, - n_classes=3, - n_informative=3, - n_redundant=0, - random_state=0, - shuffle=False, - ) - - feature_hasher = FeatureHasher(n_features=3) - features = [] - for i in range(0, 100): - features.append( - { - "a": random.randint(0, 2), - "b": random.randint(3, 5), - "c": random.randint(6, 8), - } - ) - self.y_sparse = [random.randint(0, 2) for i in range(0, 100)] - self.X_sparse = feature_hasher.transform(features) - +X, y = make_classification( + n_samples=50, + n_features=3, + n_classes=3, + n_informative=3, + n_redundant=0, + random_state=0, + shuffle=False, +) + +feature_hasher = FeatureHasher(n_features=3) +features = [] +for i in range(0, 100): + features.append( + { + "a": random.randint(0, 2), + "b": random.randint(3, 5), + "c": random.randint(6, 8), + } + ) +y_sparse = [random.randint(0, 2) for i in range(0, 100)] +X_sparse = feature_hasher.transform(features) + + +class TestClassification: def check_model(self, model, abs=False): # Given if abs: - model.fit(np.absolute(self.X), self.y) + model.fit(np.absolute(X), y) else: - model.fit(self.X, self.y) + model.fit(X, y) # When serialized_model = skljson.to_dict(model) deserialized_model = skljson.from_dict(serialized_model) # Then - expected_predictions = model.predict(self.X) - actual_predictions = deserialized_model.predict(self.X) + expected_predictions = model.predict(X) + actual_predictions = deserialized_model.predict(X) testing.assert_array_equal(expected_predictions, actual_predictions) def check_sparse_model(self, model, abs=False): # Given if abs: - model.fit(np.absolute(self.X_sparse), self.y_sparse) + model.fit(np.absolute(X_sparse), y_sparse) else: - model.fit(self.X_sparse, self.y_sparse) + model.fit(X_sparse, y_sparse) # When serialized_model = skljson.to_dict(model) deserialized_model = skljson.from_dict(serialized_model) # Then - expected_predictions = model.predict(self.X) - actual_predictions = deserialized_model.predict(self.X) + expected_predictions = model.predict(X) + actual_predictions = deserialized_model.predict(X) testing.assert_array_equal(expected_predictions, actual_predictions) def check_model_json(self, model, model_name, abs=False): # Given if abs: - model.fit(np.absolute(self.X), self.y) + model.fit(np.absolute(X), y) else: - model.fit(self.X, self.y) + model.fit(X, y) # When skljson.to_json(model, model_name) deserialized_model = skljson.from_json(model_name) # Then - expected_predictions = model.predict(self.X) - actual_predictions = deserialized_model.predict(self.X) + expected_predictions = model.predict(X) + actual_predictions = deserialized_model.predict(X) testing.assert_array_equal(expected_predictions, actual_predictions) def check_sparse_model_json(self, model, model_name, abs=False): # Given if abs: - model.fit(np.absolute(self.X_sparse), self.y_sparse) + model.fit(np.absolute(X_sparse), y_sparse) else: - model.fit(self.X_sparse, self.y_sparse) + model.fit(X_sparse, y_sparse) # When skljson.to_json(model, model_name) deserialized_model = skljson.from_json(model_name) # Then - expected_predictions = model.predict(self.X) - actual_predictions = deserialized_model.predict(self.X) + expected_predictions = model.predict(X) + actual_predictions = deserialized_model.predict(X) testing.assert_array_equal(expected_predictions, actual_predictions) From 3385deb2db37b98ef98f527ce4c6f7897fe5b596 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 21 Jun 2023 16:29:46 -0400 Subject: [PATCH 5/6] Use tmp file for tests --- test/test_classification.py | 82 +++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/test/test_classification.py b/test/test_classification.py index 63ca7f0..9dc92db 100644 --- a/test/test_classification.py +++ b/test/test_classification.py @@ -1,6 +1,7 @@ import random import numpy as np +import pytest from numpy import testing from sklearn import discriminant_analysis, svm from sklearn.datasets import make_classification @@ -37,6 +38,7 @@ X_sparse = feature_hasher.transform(features) +@pytest.mark.usefixtures("tmp_path") class TestClassification: def check_model(self, model, abs=False): # Given @@ -72,7 +74,7 @@ def check_sparse_model(self, model, abs=False): testing.assert_array_equal(expected_predictions, actual_predictions) - def check_model_json(self, model, model_name, abs=False): + def check_model_json(self, model, model_name, tmp_path, abs=False): # Given if abs: model.fit(np.absolute(X), y) @@ -80,8 +82,8 @@ def check_model_json(self, model, model_name, abs=False): model.fit(X, y) # When - skljson.to_json(model, model_name) - deserialized_model = skljson.from_json(model_name) + skljson.to_json(model, tmp_path / model_name) + deserialized_model = skljson.from_json(tmp_path / model_name) # Then expected_predictions = model.predict(X) @@ -89,7 +91,7 @@ def check_model_json(self, model, model_name, abs=False): testing.assert_array_equal(expected_predictions, actual_predictions) - def check_sparse_model_json(self, model, model_name, abs=False): + def check_sparse_model_json(self, model, model_name, tmp_path, abs=False): # Given if abs: model.fit(np.absolute(X_sparse), y_sparse) @@ -97,8 +99,8 @@ def check_sparse_model_json(self, model, model_name, abs=False): model.fit(X_sparse, y_sparse) # When - skljson.to_json(model, model_name) - deserialized_model = skljson.from_json(model_name) + skljson.to_json(model, tmp_path / model_name) + deserialized_model = skljson.from_json(tmp_path / model_name) # Then expected_predictions = model.predict(X) @@ -106,93 +108,93 @@ def check_sparse_model_json(self, model, model_name, abs=False): testing.assert_array_equal(expected_predictions, actual_predictions) - def test_bernoulli_nb(self): + def test_bernoulli_nb(self, tmp_path): self.check_model(BernoulliNB()) self.check_sparse_model(BernoulliNB()) model_name = "bernoulli-nb.json" - self.check_model_json(BernoulliNB(), model_name) - self.check_sparse_model_json(BernoulliNB(), model_name) + self.check_model_json(BernoulliNB(), model_name, tmp_path) + self.check_sparse_model_json(BernoulliNB(), model_name, tmp_path) - def test_guassian_nb(self): + def test_guassian_nb(self, tmp_path): self.check_model(GaussianNB()) model_name = "gaussian-nb.json" - self.check_model_json(GaussianNB(), model_name) + self.check_model_json(GaussianNB(), model_name, tmp_path) # No sklearn implementation for sparse matrix - def test_multinomial_nb(self): + def test_multinomial_nb(self, tmp_path): self.check_model(MultinomialNB(), abs=True) self.check_sparse_model(MultinomialNB(), abs=True) model_name = "multinomial-nb.json" - self.check_model_json(MultinomialNB(), model_name, abs=True) - self.check_sparse_model_json(MultinomialNB(), model_name, abs=True) + self.check_model_json(MultinomialNB(), model_name, tmp_path, abs=True) + self.check_sparse_model_json(MultinomialNB(), model_name, tmp_path, abs=True) - def test_complement_nb(self): + def test_complement_nb(self, tmp_path): self.check_model(ComplementNB(), abs=True) model_name = "complement-nb.json" - self.check_model_json(ComplementNB(), model_name, abs=True) + self.check_model_json(ComplementNB(), model_name, tmp_path, abs=True) # No sklearn implementation for sparse matrix - def test_logistic_regression(self): + def test_logistic_regression(self, tmp_path): self.check_model(LogisticRegression()) self.check_sparse_model(LogisticRegression()) model_name = "lr.json" - self.check_model_json(LogisticRegression(), model_name) - self.check_sparse_model_json(LogisticRegression(), model_name) + self.check_model_json(LogisticRegression(), model_name, tmp_path) + self.check_sparse_model_json(LogisticRegression(), model_name, tmp_path) - def test_lda(self): + def test_lda(self, tmp_path): self.check_model(discriminant_analysis.LinearDiscriminantAnalysis()) model_name = "lda.json" self.check_model_json( - discriminant_analysis.LinearDiscriminantAnalysis(), model_name + discriminant_analysis.LinearDiscriminantAnalysis(), model_name, tmp_path ) # No sklearn implementation for sparse matrix - def test_qda(self): + def test_qda(self, tmp_path): self.check_model(discriminant_analysis.QuadraticDiscriminantAnalysis()) model_name = "qda.json" self.check_model_json( - discriminant_analysis.QuadraticDiscriminantAnalysis(), model_name + discriminant_analysis.QuadraticDiscriminantAnalysis(), model_name, tmp_path ) # No sklearn implementation for sparse matrix - def test_svm(self): + def test_svm(self, tmp_path): self.check_model(svm.SVC(gamma=0.001, C=100.0, kernel="linear")) self.check_sparse_model(svm.SVC(gamma=0.001, C=100.0, kernel="linear")) model_name = "svm.json" - self.check_model_json(svm.SVC(), model_name) - self.check_sparse_model_json(svm.SVC(), model_name) + self.check_model_json(svm.SVC(), model_name, tmp_path) + self.check_sparse_model_json(svm.SVC(), model_name, tmp_path) - def test_decision_tree(self): + def test_decision_tree(self, tmp_path): self.check_model(DecisionTreeClassifier()) self.check_sparse_model(DecisionTreeClassifier()) model_name = "dt.json" - self.check_model_json(DecisionTreeClassifier(), model_name) - self.check_sparse_model_json(DecisionTreeClassifier(), model_name) + self.check_model_json(DecisionTreeClassifier(), model_name, tmp_path) + self.check_sparse_model_json(DecisionTreeClassifier(), model_name, tmp_path) - def test_gradient_boosting(self): + def test_gradient_boosting(self, tmp_path): self.check_model(GradientBoostingClassifier(n_estimators=25, learning_rate=1.0)) self.check_sparse_model( GradientBoostingClassifier(n_estimators=25, learning_rate=1.0) ) model_name = "gb.json" - self.check_model_json(GradientBoostingClassifier(), model_name) - self.check_sparse_model_json(GradientBoostingClassifier(), model_name) + self.check_model_json(GradientBoostingClassifier(), model_name, tmp_path) + self.check_sparse_model_json(GradientBoostingClassifier(), model_name, tmp_path) - def test_random_forest(self): + def test_random_forest(self, tmp_path): self.check_model( RandomForestClassifier(n_estimators=10, max_depth=5, random_state=0) ) @@ -201,18 +203,18 @@ def test_random_forest(self): ) model_name = "rf.json" - self.check_model_json(RandomForestClassifier(), model_name) - self.check_sparse_model_json(RandomForestClassifier(), model_name) + self.check_model_json(RandomForestClassifier(), model_name, tmp_path) + self.check_sparse_model_json(RandomForestClassifier(), model_name, tmp_path) - def test_perceptron(self): + def test_perceptron(self, tmp_path): self.check_model(Perceptron()) self.check_sparse_model(Perceptron()) model_name = "perceptron.json" - self.check_model_json(Perceptron(), model_name) - self.check_sparse_model_json(Perceptron(), model_name) + self.check_model_json(Perceptron(), model_name, tmp_path) + self.check_sparse_model_json(Perceptron(), model_name, tmp_path) - def test_mlp(self): + def test_mlp(self, tmp_path): self.check_model( MLPClassifier( solver="lbfgs", alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1 @@ -230,10 +232,12 @@ def test_mlp(self): solver="lbfgs", alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1 ), model_name, + tmp_path, ) self.check_sparse_model_json( MLPClassifier( solver="lbfgs", alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1 ), model_name, + tmp_path, ) From 36e60d4d05072f3d56fd8246f45e683428c24bbc Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 22 Jun 2023 15:09:54 -0400 Subject: [PATCH 6/6] Fix SVR and tests --- sklearn_json/classification.py | 6 ++-- sklearn_json/regression.py | 65 +++++++++++++++++----------------- test/test_regression.py | 54 ++++++++++++++-------------- 3 files changed, 63 insertions(+), 62 deletions(-) diff --git a/sklearn_json/classification.py b/sklearn_json/classification.py index b6b93fc..da90939 100644 --- a/sklearn_json/classification.py +++ b/sklearn_json/classification.py @@ -395,11 +395,11 @@ def serialize_gradient_boosting(model): elif isinstance(model.init_, str): serialized_model["init_"] = model.init_ - if isinstance(model.loss_, _gb_losses.BinomialDeviance): + if isinstance(model._loss, _gb_losses.BinomialDeviance): serialized_model["loss_"] = "deviance" - elif isinstance(model.loss_, _gb_losses.ExponentialLoss): + elif isinstance(model._loss, _gb_losses.ExponentialLoss): serialized_model["loss_"] = "exponential" - elif isinstance(model.loss_, _gb_losses.MultinomialDeviance): + elif isinstance(model._loss, _gb_losses.MultinomialDeviance): serialized_model["loss_"] = "multinomial" if "priors" in model.init_.__dict__: diff --git a/sklearn_json/regression.py b/sklearn_json/regression.py index 4c0abc7..0608d45 100644 --- a/sklearn_json/regression.py +++ b/sklearn_json/regression.py @@ -27,7 +27,7 @@ def serialize_linear_regressor(model): def deserialize_linear_regressor(model_dict): - model = LinearRegression(model_dict["params"]) + model = LinearRegression(**model_dict["params"]) model.coef_ = np.array(model_dict["coef_"]) model.intercept_ = np.array(model_dict["intercept_"]) @@ -110,17 +110,20 @@ def deserialize_ridge_regressor(model_dict): def serialize_svr(model): serialized_model = { "meta": "svr", - "class_weight_": model.class_weight_.tolist(), - "support_": model.support_.tolist(), - "n_support_": model.n_support_.tolist(), - "intercept_": model.intercept_.tolist(), - "probA_": model.probA_.tolist(), - "probB_": model.probB_.tolist(), - "_intercept_": model._intercept_.tolist(), - "shape_fit_": model.shape_fit_, - "_gamma": model._gamma, "params": model.get_params(), } + serialized_model.update( + { + k: ( + v.tolist() + if isinstance(v, np.ndarray) + else int(v) + if isinstance(v, np.int64) + else v + ) + for k, v in vars(model).items() + } + ) if isinstance(model.support_vectors_, sp.sparse.csr_matrix): serialized_model["support_vectors_"] = csr.serialize_csr_matrix( @@ -144,16 +147,13 @@ def serialize_svr(model): def deserialize_svr(model_dict): model = SVR(**model_dict["params"]) - model.shape_fit_ = model_dict["shape_fit_"] - model._gamma = model_dict["_gamma"] - - model.class_weight_ = np.array(model_dict["class_weight_"]).astype(np.float64) - model.support_ = np.array(model_dict["support_"]).astype(np.int32) - model.n_support_ = np.array(model_dict["n_support_"]).astype(np.int32) - model.intercept_ = np.array(model_dict["intercept_"]).astype(np.float64) - model.probA_ = np.array(model_dict["probA_"]).astype(np.float64) - model.probB_ = np.array(model_dict["probB_"]).astype(np.float64) - model._intercept_ = np.array(model_dict["_intercept_"]).astype(np.float64) + attrs = [k for k in model_dict if k not in model_dict["params"]] + for attr in attrs: + if isinstance(model_dict[attr], list): + attr_val = np.array(model_dict[attr]) + else: + attr_val = model_dict[attr] + setattr(model, attr, attr_val) if ( "meta" in model_dict["support_vectors_"] @@ -182,6 +182,10 @@ def deserialize_svr(model_dict): else: model._dual_coef_ = np.array(model_dict["_dual_coef_"]).astype(np.float64) + for k, v in vars(model).items(): + if isinstance(v, np.ndarray) and v.dtype == np.int64: + setattr(model, k, v.astype(np.int32)) + return model @@ -278,13 +282,13 @@ def serialize_gradient_boosting_regressor(model): elif isinstance(model.init_, str): serialized_model["init_"] = model.init_ - if isinstance(model.loss_, _gb_losses.LeastSquaresError): + if isinstance(model._loss, _gb_losses.LeastSquaresError): serialized_model["loss_"] = "ls" - elif isinstance(model.loss_, _gb_losses.LeastAbsoluteError): + elif isinstance(model._loss, _gb_losses.LeastAbsoluteError): serialized_model["loss_"] = "lad" - elif isinstance(model.loss_, _gb_losses.HuberLossFunction): + elif isinstance(model._loss, _gb_losses.HuberLossFunction): serialized_model["loss_"] = "huber" - elif isinstance(model.loss_, _gb_losses.QuantileLossFunction): + elif isinstance(model._loss, _gb_losses.QuantileLossFunction): serialized_model["loss_"] = "quantile" if "priors" in model.init_.__dict__: @@ -310,13 +314,13 @@ def deserialize_gradient_boosting_regressor(model_dict): model.max_features_ = model_dict["max_features_"] model.n_features_in_ = model_dict["n_features_in_"] if model_dict["loss_"] == "ls": - model.loss_ = _gb_losses.LeastSquaresError(1) + model._loss = _gb_losses.LeastSquaresError() elif model_dict["loss_"] == "lad": - model.loss_ = _gb_losses.LeastAbsoluteError(1) + model._loss = _gb_losses.LeastAbsoluteError() elif model_dict["loss_"] == "huber": - model.loss_ = _gb_losses.HuberLossFunction(1) + model._loss = _gb_losses.HuberLossFunction() elif model_dict["loss_"] == "quantile": - model.loss_ = _gb_losses.QuantileLossFunction(1) + model._loss = _gb_losses.QuantileLossFunction() if "priors" in model_dict: model.init_.priors = np.array(model_dict["priors"]) @@ -333,9 +337,8 @@ def serialize_random_forest_regressor(model): "max_features": model.max_features, "max_leaf_nodes": model.max_leaf_nodes, "min_impurity_decrease": model.min_impurity_decrease, - "min_impurity_split": model.min_impurity_split, - "n_features_in_": model.n_features_in_, "n_outputs_": model.n_outputs_, + "n_features_in_": model.n_features_in_, "estimators_": [ serialize_decision_tree_regressor(decision_tree) for decision_tree in model.estimators_ @@ -358,7 +361,6 @@ def deserialize_random_forest_regressor(model_dict): for decision_tree in model_dict["estimators_"] ] model.estimators_ = np.array(estimators) - model.n_features_in_ = model_dict["n_features_in_"] model.n_outputs_ = model_dict["n_outputs_"] model.max_depth = model_dict["max_depth"] @@ -368,7 +370,6 @@ def deserialize_random_forest_regressor(model_dict): model.max_features = model_dict["max_features"] model.max_leaf_nodes = model_dict["max_leaf_nodes"] model.min_impurity_decrease = model_dict["min_impurity_decrease"] - model.min_impurity_split = model_dict["min_impurity_split"] if "oob_score_" in model_dict: model.oob_score_ = model_dict["oob_score_"] diff --git a/test/test_regression.py b/test/test_regression.py index 9698680..1de9296 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -1,6 +1,6 @@ import random -import unittest +import pytest from numpy import testing from sklearn.datasets import make_regression from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor @@ -12,51 +12,51 @@ import sklearn_json as skljson - -class TestAPI(unittest.TestCase): - def setUp(self): - self.X, self.y = make_regression( - n_samples=50, n_features=3, n_informative=3, random_state=0, shuffle=False - ) - - feature_hasher = FeatureHasher(n_features=3) - features = [] - for i in range(0, 100): - features.append( - { - "a": random.randint(0, 2), - "b": random.randint(3, 5), - "c": random.randint(6, 8), - } - ) - self.y_sparse = [random.random() for i in range(0, 100)] - self.X_sparse = feature_hasher.transform(features) - +X, y = make_regression( + n_samples=50, n_features=3, n_informative=3, random_state=0, shuffle=False +) + +feature_hasher = FeatureHasher(n_features=3) +features = [] +for i in range(0, 100): + features.append( + { + "a": random.randint(0, 2), + "b": random.randint(3, 5), + "c": random.randint(6, 8), + } + ) +y_sparse = [random.random() for i in range(0, 100)] +X_sparse = feature_hasher.transform(features) + + +@pytest.mark.usefixtures("tmp_path") +class TestRegression: def check_model(self, model): # Given - model.fit(self.X, self.y) + model.fit(X, y) # When serialized_model = skljson.to_dict(model) deserialized_model = skljson.from_dict(serialized_model) # Then - expected_predictions = model.predict(self.X) - actual_predictions = deserialized_model.predict(self.X) + expected_predictions = model.predict(X) + actual_predictions = deserialized_model.predict(X) testing.assert_array_equal(expected_predictions, actual_predictions) def check_sparse_model(self, model): # Given - model.fit(self.X_sparse, self.y_sparse) + model.fit(X_sparse, y_sparse) # When serialized_model = skljson.to_dict(model) deserialized_model = skljson.from_dict(serialized_model) # Then - expected_predictions = model.predict(self.X_sparse) - actual_predictions = deserialized_model.predict(self.X_sparse) + expected_predictions = model.predict(X_sparse) + actual_predictions = deserialized_model.predict(X_sparse) testing.assert_array_equal(expected_predictions, actual_predictions)