From d7bbaec52a779397720b59a9f344923f39db79e2 Mon Sep 17 00:00:00 2001 From: joaquin Date: Mon, 17 Jun 2024 20:31:06 +0200 Subject: [PATCH 01/33] user dot/4 on set_intercept --- lib/scholar/linear/linear_helpers.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index cbe60e53..e038fa5e 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -33,7 +33,7 @@ defmodule Scholar.Linear.LinearHelpers do @doc false defn set_intercept(coeff, x_offset, y_offset, fit_intercept?) do if fit_intercept? do - y_offset - Nx.dot(coeff, x_offset) + y_offset - Nx.dot(coeff, [-1], x_offset, [-1]) else Nx.tensor(0.0, type: Nx.type(coeff)) end From 3cf37fcf4ba64220367e8709be11a28403a408d9 Mon Sep 17 00:00:00 2001 From: joaquin Date: Mon, 17 Jun 2024 20:36:26 +0200 Subject: [PATCH 02/33] use dot/4 on linear regression predict --- lib/scholar/linear/linear_regression.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scholar/linear/linear_regression.ex b/lib/scholar/linear/linear_regression.ex index 59885ba3..761fced0 100644 --- a/lib/scholar/linear/linear_regression.ex +++ b/lib/scholar/linear/linear_regression.ex @@ -124,7 +124,7 @@ defmodule Scholar.Linear.LinearRegression do ) """ defn predict(%__MODULE__{coefficients: coeff, intercept: intercept} = _model, x) do - Nx.dot(x, coeff) + intercept + Nx.dot(x, [-1], coeff, [-1]) + intercept end # Implements ordinary least-squares by estimating the From d3ded77b62f484b3830a5c844ce553a8f81912ff Mon Sep 17 00:00:00 2001 From: joaquin Date: Mon, 17 Jun 2024 23:10:20 +0200 Subject: [PATCH 03/33] add column target tests --- .../linear/bayesian_ridge_regression_test.exs | 12 ++++++++++++ test/scholar/linear/isotonic_regression_test.exs | 10 ++++++++++ test/scholar/linear/linear_regression_test.exs | 13 +++++++++++++ test/scholar/linear/svm_test.exs | 10 ++++++++++ 4 files changed, 45 insertions(+) diff --git a/test/scholar/linear/bayesian_ridge_regression_test.exs b/test/scholar/linear/bayesian_ridge_regression_test.exs index 845bbf74..a363009d 100644 --- a/test/scholar/linear/bayesian_ridge_regression_test.exs +++ b/test/scholar/linear/bayesian_ridge_regression_test.exs @@ -15,6 +15,18 @@ defmodule Scholar.Linear.BayesianRidgeRegressionTest do assert_all_close(expected, predicted, atol: 1.0e-1) end + @tag :wip + test "toy bayesian ridge with column target" do + x = Nx.tensor([[1], [2], [6], [8], [10]]) + y = Nx.tensor([1, 2, 6, 8, 10]) |> Nx.new_axis(-1) + clf = BayesianRidgeRegression.fit(x, y) + test = Nx.tensor([[1], [3], [4]]) + expected = Nx.tensor([1, 3, 4]) |> Nx.new_axis(-1) + predicted = BayesianRidgeRegression.predict(clf, test) + assert_all_close(expected, predicted, atol: 1.0e-1) + end + + test "ridge vs bayesian ridge: parameters" do x = Nx.tensor([[1, 1], [3, 4], [5, 7], [4, 1], [2, 6], [3, 10], [3, 2]]) y = Nx.tensor([1, 2, 3, 2, 0, 4, 5]) diff --git a/test/scholar/linear/isotonic_regression_test.exs b/test/scholar/linear/isotonic_regression_test.exs index a954a0bd..52605a03 100644 --- a/test/scholar/linear/isotonic_regression_test.exs +++ b/test/scholar/linear/isotonic_regression_test.exs @@ -91,6 +91,16 @@ defmodule Scholar.Linear.IsotonicRegressionTest do assert model.preprocess == {} end + @tag :wip + test "fit column vector" do + x = Nx.tensor([2.0, 2.0, 3.0, 4.0, 5.0]) + y = Nx.tensor([2.0, 3.0, 7.0, 8.0, 9.0]) |> Nx.new_axis(-1) + sample_weights = Nx.tensor([1, 3, 2, 7, 4]) + model = IsotonicRegression.fit(x, y, sample_weights: sample_weights) + IO.inspect(model) + assert false + end + test "fit with sample_weights and :increasing? set to false" do x = Nx.tensor([2.0, 2.0, 3.0, 4.0, 5.0, 5.0, 6.0]) y = Nx.tensor([11, 12, 9, 7, 5, 4, 2]) diff --git a/test/scholar/linear/linear_regression_test.exs b/test/scholar/linear/linear_regression_test.exs index 2dbdb1c8..319c9339 100644 --- a/test/scholar/linear/linear_regression_test.exs +++ b/test/scholar/linear/linear_regression_test.exs @@ -895,4 +895,17 @@ defmodule Scholar.Linear.LinearRegressionTest do assert_all_close(expected_prediction, actual_prediction, rtol: 1.0e-3, atol: 1.0e-3) end end + + describe "fit and predict with colum target" do + @tag :wip + test "test column target" do + x = Nx.tensor([[1], [2], [6], [8], [10]]) + y = Nx.tensor([1, 2, 6, 8, 10]) |> Nx.new_axis(-1) + lr = LinearRegression.fit(x, y) + test = Nx.tensor([[1], [3], [4]]) + expected = Nx.tensor([1, 3, 4]) |> Nx.new_axis(-1) + predicted = LinearRegression.predict(lr, test) + assert_all_close(expected, predicted, atol: 1.0e-1) + end + end end diff --git a/test/scholar/linear/svm_test.exs b/test/scholar/linear/svm_test.exs index d532d456..82b84a59 100644 --- a/test/scholar/linear/svm_test.exs +++ b/test/scholar/linear/svm_test.exs @@ -17,4 +17,14 @@ defmodule Scholar.Linear.SVMTest do assert Nx.greater_equal(accuracy, 0.96) == Nx.u8(1) end + @tag :wip + test "test column target" do + x = Nx.tensor([[1], [2], [6], [8], [10]]) + y = Nx.tensor([1, 2, 6, 8, 10]) |> Nx.new_axis(-1) + svm = SVM.fit(x, y) + test = Nx.tensor([[1], [3], [4]]) + expected = Nx.tensor([1, 3, 4]) |> Nx.new_axis(-1) + predicted = SVM.predict(svm, test) + assert_all_close(expected, predicted, atol: 1.0e-1) + end end From feb7e5fe507ff364842239a60cd7951f6ea18486 Mon Sep 17 00:00:00 2001 From: joaquin Date: Mon, 17 Jun 2024 23:10:59 +0200 Subject: [PATCH 04/33] better name for test --- test/scholar/linear/isotonic_regression_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/scholar/linear/isotonic_regression_test.exs b/test/scholar/linear/isotonic_regression_test.exs index 52605a03..ab5b42de 100644 --- a/test/scholar/linear/isotonic_regression_test.exs +++ b/test/scholar/linear/isotonic_regression_test.exs @@ -92,7 +92,7 @@ defmodule Scholar.Linear.IsotonicRegressionTest do end @tag :wip - test "fit column vector" do + test "fit column target" do x = Nx.tensor([2.0, 2.0, 3.0, 4.0, 5.0]) y = Nx.tensor([2.0, 3.0, 7.0, 8.0, 9.0]) |> Nx.new_axis(-1) sample_weights = Nx.tensor([1, 3, 2, 7, 4]) From c80322327fd535a91e00bb4c034a70b41936235b Mon Sep 17 00:00:00 2001 From: joaquin Date: Sat, 22 Jun 2024 21:34:18 +0200 Subject: [PATCH 05/33] working on svm --- lib/scholar/linear/svm.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/scholar/linear/svm.ex b/lib/scholar/linear/svm.ex index 688c034b..636eb836 100644 --- a/lib/scholar/linear/svm.ex +++ b/lib/scholar/linear/svm.ex @@ -122,7 +122,9 @@ defmodule Scholar.Linear.SVM do "expected x to have shape {n_samples, n_features}, got tensor with shape: #{inspect(Nx.shape(x))}" end - if Nx.rank(y) != 1 do + is_column_vector? = (elem(Nx.shape(y), 1) == 1) and (Nx.rank(y) == 2) + is_valid_target? = (Nx.rank(y) == 1) or is_column_vector? + if not is_valid_target? do raise ArgumentError, "expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" end From 4cde60be0ddbe5a51e00af51a1c7431052b56632 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sat, 22 Jun 2024 23:04:56 +0200 Subject: [PATCH 06/33] svm supports multioutput --- lib/scholar/linear/svm.ex | 5 +++-- test/scholar/linear/svm_test.exs | 21 +++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/scholar/linear/svm.ex b/lib/scholar/linear/svm.ex index 636eb836..ba9ddcd5 100644 --- a/lib/scholar/linear/svm.ex +++ b/lib/scholar/linear/svm.ex @@ -122,7 +122,8 @@ defmodule Scholar.Linear.SVM do "expected x to have shape {n_samples, n_features}, got tensor with shape: #{inspect(Nx.shape(x))}" end - is_column_vector? = (elem(Nx.shape(y), 1) == 1) and (Nx.rank(y) == 2) + {num_samples, _} = Nx.shape(x) + is_column_vector? = (Nx.shape(y) == {num_samples, 1}) and (Nx.rank(y) == 2) is_valid_target? = (Nx.rank(y) == 1) or is_column_vector? if not is_valid_target? do raise ArgumentError, @@ -187,7 +188,7 @@ defmodule Scholar.Linear.SVM do while {{coef, bias, has_converged, coef_optimizer_state, bias_optimizer_state}, {x, y, iterations, iter, eps, j = 0}}, j < num_classes do - y_j = y == j + y_j = (y |> Nx.flatten) == j coef_j = Nx.take(coef, j) bias_j = Nx.take(bias, j) diff --git a/test/scholar/linear/svm_test.exs b/test/scholar/linear/svm_test.exs index 82b84a59..f3c8773d 100644 --- a/test/scholar/linear/svm_test.exs +++ b/test/scholar/linear/svm_test.exs @@ -9,7 +9,6 @@ defmodule Scholar.Linear.SVMTest do loss_fn = fn y_pred, y_true -> Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) end - model = SVM.fit(x_train, y_train, num_classes: 3, loss_fn: loss_fn) res = SVM.predict(model, x_test) @@ -18,13 +17,19 @@ defmodule Scholar.Linear.SVMTest do assert Nx.greater_equal(accuracy, 0.96) == Nx.u8(1) end @tag :wip + @tag :svmwip test "test column target" do - x = Nx.tensor([[1], [2], [6], [8], [10]]) - y = Nx.tensor([1, 2, 6, 8, 10]) |> Nx.new_axis(-1) - svm = SVM.fit(x, y) - test = Nx.tensor([[1], [3], [4]]) - expected = Nx.tensor([1, 3, 4]) |> Nx.new_axis(-1) - predicted = SVM.predict(svm, test) - assert_all_close(expected, predicted, atol: 1.0e-1) + {x_train, x_test, y_train, y_test} = iris_data() + + loss_fn = fn y_pred, y_true -> + Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) + end + model = SVM.fit(x_train, y_train |> Nx.new_axis(-1), + num_classes: 3, loss_fn: loss_fn) + res = SVM.predict(model, x_test) + + accuracy = Scholar.Metrics.Classification.accuracy(res, y_test) + + assert Nx.greater_equal(accuracy, 0.96) == Nx.u8(1) end end From 0f1c0f7e1c1a2f469aea7d6c51683021af76b742 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 30 Jun 2024 13:13:58 +0200 Subject: [PATCH 07/33] check col and regular models are the same. invalid y raises --- test/scholar/linear/svm_test.exs | 33 ++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/test/scholar/linear/svm_test.exs b/test/scholar/linear/svm_test.exs index f3c8773d..b64ab4e1 100644 --- a/test/scholar/linear/svm_test.exs +++ b/test/scholar/linear/svm_test.exs @@ -5,10 +5,10 @@ defmodule Scholar.Linear.SVMTest do test "Iris Data Set - multinomial classification svm test" do {x_train, x_test, y_train, y_test} = iris_data() - loss_fn = fn y_pred, y_true -> Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) - end + end + model = SVM.fit(x_train, y_train, num_classes: 3, loss_fn: loss_fn) res = SVM.predict(model, x_test) @@ -16,20 +16,41 @@ defmodule Scholar.Linear.SVMTest do assert Nx.greater_equal(accuracy, 0.96) == Nx.u8(1) end - @tag :wip - @tag :svmwip + test "test column target" do {x_train, x_test, y_train, y_test} = iris_data() loss_fn = fn y_pred, y_true -> Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) end - model = SVM.fit(x_train, y_train |> Nx.new_axis(-1), + col_model = SVM.fit(x_train, y_train |> Nx.new_axis(-1), num_classes: 3, loss_fn: loss_fn) - res = SVM.predict(model, x_test) + res = SVM.predict(col_model, x_test) + + model = SVM.fit(x_train, y_train, num_classes: 3, loss_fn: loss_fn) accuracy = Scholar.Metrics.Classification.accuracy(res, y_test) assert Nx.greater_equal(accuracy, 0.96) == Nx.u8(1) + assert model == col_model + end + + test "test fit 2 columned y data" do + {x_train, _, y_train, _} = iris_data() + + loss_fn = fn y_pred, y_true -> + Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) + end + y_train = Nx.concatenate( + [y_train |> Nx.new_axis(-1), y_train |> Nx.new_axis(-1)], + axis: 1 + ) + {n_samples, _} = Nx.shape(x_train) + message = "Elixir.#{inspect(SVM)} expected y to have shape #{n_samples}, got tensor with shape: #{inspect(Nx.shape(y_train))}" + assert_raise ArgumentError, + message, + fn -> SVM.fit(x_train, y_train, num_classes: 3, loss_fn: loss_fn) + end end + end From d09fb53e8b21d2f716e77274d384619b1dae1f33 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 30 Jun 2024 13:14:30 +0200 Subject: [PATCH 08/33] move y shape validation to linear_helper function --- lib/scholar/linear/svm.ex | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/scholar/linear/svm.ex b/lib/scholar/linear/svm.ex index ba9ddcd5..9ab4ae6f 100644 --- a/lib/scholar/linear/svm.ex +++ b/lib/scholar/linear/svm.ex @@ -19,6 +19,7 @@ defmodule Scholar.Linear.SVM do """ import Nx.Defn import Scholar.Shared + alias Scholar.Linear.LinearHelpers @derive {Nx.Container, containers: [:coefficients, :bias]} defstruct [:coefficients, :bias] @@ -122,13 +123,7 @@ defmodule Scholar.Linear.SVM do "expected x to have shape {n_samples, n_features}, got tensor with shape: #{inspect(Nx.shape(x))}" end - {num_samples, _} = Nx.shape(x) - is_column_vector? = (Nx.shape(y) == {num_samples, 1}) and (Nx.rank(y) == 2) - is_valid_target? = (Nx.rank(y) == 1) or is_column_vector? - if not is_valid_target? do - raise ArgumentError, - "expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" - end + y = LinearHelpers.validate_y_shape(x, y, __MODULE__) opts = NimbleOptions.validate!(opts, @opts_schema) From 07626ea35634a1012abfe0a9d91a49da1530bd5f Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 30 Jun 2024 13:14:51 +0200 Subject: [PATCH 09/33] add linear helper function for shape validation --- lib/scholar/linear/linear_helpers.ex | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index e038fa5e..9554c607 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -5,6 +5,19 @@ defmodule Scholar.Linear.LinearHelpers do @moduledoc false + @doc false + def validate_y_shape(x, y, module_name) do + {n_samples, _} = Nx.shape(x) + is_column_vector? = (Nx.shape(y) == {n_samples, 1}) and (Nx.rank(y) == 2) + is_valid_target? = (Nx.rank(y) == 1) or is_column_vector? + if not is_valid_target? do + message = "#{module_name} expected y to have shape #{n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + raise ArgumentError, message + else + y |> Nx.flatten() + end + end + @doc false def build_sample_weights(x, opts) do x_type = to_float_type(x) From d3319fac53b8165e73e268b45d5e78618d96b967 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 30 Jun 2024 13:15:48 +0200 Subject: [PATCH 10/33] formatter --- lib/scholar/linear/linear_helpers.ex | 9 +++-- lib/scholar/linear/svm.ex | 4 +-- .../linear/bayesian_ridge_regression_test.exs | 1 - test/scholar/linear/svm_test.exs | 33 +++++++++++-------- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index 9554c607..6a3c1657 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -8,10 +8,13 @@ defmodule Scholar.Linear.LinearHelpers do @doc false def validate_y_shape(x, y, module_name) do {n_samples, _} = Nx.shape(x) - is_column_vector? = (Nx.shape(y) == {n_samples, 1}) and (Nx.rank(y) == 2) - is_valid_target? = (Nx.rank(y) == 1) or is_column_vector? + is_column_vector? = Nx.shape(y) == {n_samples, 1} and Nx.rank(y) == 2 + is_valid_target? = Nx.rank(y) == 1 or is_column_vector? + if not is_valid_target? do - message = "#{module_name} expected y to have shape #{n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + message = + "#{module_name} expected y to have shape #{n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + raise ArgumentError, message else y |> Nx.flatten() diff --git a/lib/scholar/linear/svm.ex b/lib/scholar/linear/svm.ex index 9ab4ae6f..f30d06c4 100644 --- a/lib/scholar/linear/svm.ex +++ b/lib/scholar/linear/svm.ex @@ -19,7 +19,7 @@ defmodule Scholar.Linear.SVM do """ import Nx.Defn import Scholar.Shared - alias Scholar.Linear.LinearHelpers + alias Scholar.Linear.LinearHelpers @derive {Nx.Container, containers: [:coefficients, :bias]} defstruct [:coefficients, :bias] @@ -183,7 +183,7 @@ defmodule Scholar.Linear.SVM do while {{coef, bias, has_converged, coef_optimizer_state, bias_optimizer_state}, {x, y, iterations, iter, eps, j = 0}}, j < num_classes do - y_j = (y |> Nx.flatten) == j + y_j = y |> Nx.flatten() == j coef_j = Nx.take(coef, j) bias_j = Nx.take(bias, j) diff --git a/test/scholar/linear/bayesian_ridge_regression_test.exs b/test/scholar/linear/bayesian_ridge_regression_test.exs index a363009d..119e3fec 100644 --- a/test/scholar/linear/bayesian_ridge_regression_test.exs +++ b/test/scholar/linear/bayesian_ridge_regression_test.exs @@ -25,7 +25,6 @@ defmodule Scholar.Linear.BayesianRidgeRegressionTest do predicted = BayesianRidgeRegression.predict(clf, test) assert_all_close(expected, predicted, atol: 1.0e-1) end - test "ridge vs bayesian ridge: parameters" do x = Nx.tensor([[1, 1], [3, 4], [5, 7], [4, 1], [2, 6], [3, 10], [3, 2]]) diff --git a/test/scholar/linear/svm_test.exs b/test/scholar/linear/svm_test.exs index b64ab4e1..ea8e46fb 100644 --- a/test/scholar/linear/svm_test.exs +++ b/test/scholar/linear/svm_test.exs @@ -5,9 +5,10 @@ defmodule Scholar.Linear.SVMTest do test "Iris Data Set - multinomial classification svm test" do {x_train, x_test, y_train, y_test} = iris_data() + loss_fn = fn y_pred, y_true -> Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) - end + end model = SVM.fit(x_train, y_train, num_classes: 3, loss_fn: loss_fn) res = SVM.predict(model, x_test) @@ -16,15 +17,15 @@ defmodule Scholar.Linear.SVMTest do assert Nx.greater_equal(accuracy, 0.96) == Nx.u8(1) end - + test "test column target" do {x_train, x_test, y_train, y_test} = iris_data() loss_fn = fn y_pred, y_true -> Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) end - col_model = SVM.fit(x_train, y_train |> Nx.new_axis(-1), - num_classes: 3, loss_fn: loss_fn) + + col_model = SVM.fit(x_train, y_train |> Nx.new_axis(-1), num_classes: 3, loss_fn: loss_fn) res = SVM.predict(col_model, x_test) model = SVM.fit(x_train, y_train, num_classes: 3, loss_fn: loss_fn) @@ -41,16 +42,20 @@ defmodule Scholar.Linear.SVMTest do loss_fn = fn y_pred, y_true -> Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) end - y_train = Nx.concatenate( - [y_train |> Nx.new_axis(-1), y_train |> Nx.new_axis(-1)], - axis: 1 - ) + + y_train = + Nx.concatenate( + [y_train |> Nx.new_axis(-1), y_train |> Nx.new_axis(-1)], + axis: 1 + ) + {n_samples, _} = Nx.shape(x_train) - message = "Elixir.#{inspect(SVM)} expected y to have shape #{n_samples}, got tensor with shape: #{inspect(Nx.shape(y_train))}" + + message = + "Elixir.#{inspect(SVM)} expected y to have shape #{n_samples}, got tensor with shape: #{inspect(Nx.shape(y_train))}" + assert_raise ArgumentError, - message, - fn -> SVM.fit(x_train, y_train, num_classes: 3, loss_fn: loss_fn) - end - end - + message, + fn -> SVM.fit(x_train, y_train, num_classes: 3, loss_fn: loss_fn) end + end end From b315c84d8326e4305fcef37843d03d09e4db7df9 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 30 Jun 2024 13:28:56 +0200 Subject: [PATCH 11/33] clean up test --- test/scholar/linear/svm_test.exs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/scholar/linear/svm_test.exs b/test/scholar/linear/svm_test.exs index ea8e46fb..d237522f 100644 --- a/test/scholar/linear/svm_test.exs +++ b/test/scholar/linear/svm_test.exs @@ -43,16 +43,12 @@ defmodule Scholar.Linear.SVMTest do Scholar.Linear.SVM.hinge_loss(y_pred, y_true, c: 1.0, margin: 150) end + y_train = Nx.new_axis(y_train, -1) y_train = - Nx.concatenate( - [y_train |> Nx.new_axis(-1), y_train |> Nx.new_axis(-1)], - axis: 1 - ) - - {n_samples, _} = Nx.shape(x_train) + Nx.concatenate([y_train, y_train], axis: 1) message = - "Elixir.#{inspect(SVM)} expected y to have shape #{n_samples}, got tensor with shape: #{inspect(Nx.shape(y_train))}" + "Elixir.#{inspect(SVM)} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y_train))}" assert_raise ArgumentError, message, From 515453a458d1cca1abb634072fa5544681ca8214 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 30 Jun 2024 13:29:12 +0200 Subject: [PATCH 12/33] modify validate_y_shape for isotonic regression --- lib/scholar/linear/linear_helpers.ex | 5 ++--- lib/scholar/linear/svm.ex | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index 6a3c1657..315adcb5 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -6,14 +6,13 @@ defmodule Scholar.Linear.LinearHelpers do @moduledoc false @doc false - def validate_y_shape(x, y, module_name) do - {n_samples, _} = Nx.shape(x) + def validate_y_shape(y, n_samples, module_name) do is_column_vector? = Nx.shape(y) == {n_samples, 1} and Nx.rank(y) == 2 is_valid_target? = Nx.rank(y) == 1 or is_column_vector? if not is_valid_target? do message = - "#{module_name} expected y to have shape #{n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + "#{module_name} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" raise ArgumentError, message else diff --git a/lib/scholar/linear/svm.ex b/lib/scholar/linear/svm.ex index f30d06c4..8dddee20 100644 --- a/lib/scholar/linear/svm.ex +++ b/lib/scholar/linear/svm.ex @@ -123,7 +123,8 @@ defmodule Scholar.Linear.SVM do "expected x to have shape {n_samples, n_features}, got tensor with shape: #{inspect(Nx.shape(x))}" end - y = LinearHelpers.validate_y_shape(x, y, __MODULE__) + {n_samples, _} = Nx.shape(x) + y = LinearHelpers.validate_y_shape(y, n_samples, __MODULE__) opts = NimbleOptions.validate!(opts, @opts_schema) From 28bd4dd530eef29362f803950ae1700551e70320 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 30 Jun 2024 13:29:45 +0200 Subject: [PATCH 13/33] add y shape validation and test to isotonic regression --- lib/scholar/linear/isotonic_regression.ex | 5 ++++ .../linear/isotonic_regression_test.exs | 23 +++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/scholar/linear/isotonic_regression.ex b/lib/scholar/linear/isotonic_regression.ex index 631ac9e3..294f4d93 100644 --- a/lib/scholar/linear/isotonic_regression.ex +++ b/lib/scholar/linear/isotonic_regression.ex @@ -11,6 +11,7 @@ defmodule Scholar.Linear.IsotonicRegression do require Nx import Nx.Defn, except: [transform: 2] import Scholar.Shared + alias Scholar.Linear.LinearHelpers @derive { Nx.Container, @@ -143,6 +144,9 @@ defmodule Scholar.Linear.IsotonicRegression do } """ deftransform fit(x, y, opts \\ []) do + {n_samples} = Nx.shape(x) + y = LinearHelpers.validate_y_shape(y, n_samples, __MODULE__) + opts = NimbleOptions.validate!(opts, @opts_schema) opts = @@ -154,6 +158,7 @@ defmodule Scholar.Linear.IsotonicRegression do {sample_weights, opts} = Keyword.pop(opts, :sample_weights, 1.0) x_type = to_float_type(x) x = to_float(x) + y = to_float(y) sample_weights = diff --git a/test/scholar/linear/isotonic_regression_test.exs b/test/scholar/linear/isotonic_regression_test.exs index ab5b42de..bd4bf9d3 100644 --- a/test/scholar/linear/isotonic_regression_test.exs +++ b/test/scholar/linear/isotonic_regression_test.exs @@ -91,14 +91,29 @@ defmodule Scholar.Linear.IsotonicRegressionTest do assert model.preprocess == {} end - @tag :wip test "fit column target" do x = Nx.tensor([2.0, 2.0, 3.0, 4.0, 5.0]) - y = Nx.tensor([2.0, 3.0, 7.0, 8.0, 9.0]) |> Nx.new_axis(-1) + y = Nx.tensor([2.0, 3.0, 7.0, 8.0, 9.0]) sample_weights = Nx.tensor([1, 3, 2, 7, 4]) model = IsotonicRegression.fit(x, y, sample_weights: sample_weights) - IO.inspect(model) - assert false + col_model = IsotonicRegression.fit(x, y |> Nx.new_axis(-1), + sample_weights: sample_weights) + assert model == col_model + end + + test "fit 2 column target raises" do + x = Nx.tensor([2.0, 2.0, 3.0, 4.0, 5.0]) + y = Nx.tensor([2.0, 3.0, 7.0, 8.0, 9.0]) + y = Nx.new_axis(y, -1) + y = Nx.concatenate([y, y], axis: 1) + sample_weights = Nx.tensor([1, 3, 2, 7, 4]) + message = + "Elixir.#{inspect(IsotonicRegression)} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + + assert_raise ArgumentError, + message, + fn -> + IsotonicRegression.fit(x, y, sample_weights: sample_weights) end end test "fit with sample_weights and :increasing? set to false" do From 9dd1b88daad7c47b654e254036e402e833f9a277 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 30 Jun 2024 13:30:14 +0200 Subject: [PATCH 14/33] formatter --- lib/scholar/linear/isotonic_regression.ex | 4 ++-- test/scholar/linear/isotonic_regression_test.exs | 9 +++++---- test/scholar/linear/svm_test.exs | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/scholar/linear/isotonic_regression.ex b/lib/scholar/linear/isotonic_regression.ex index 294f4d93..317453ca 100644 --- a/lib/scholar/linear/isotonic_regression.ex +++ b/lib/scholar/linear/isotonic_regression.ex @@ -146,7 +146,7 @@ defmodule Scholar.Linear.IsotonicRegression do deftransform fit(x, y, opts \\ []) do {n_samples} = Nx.shape(x) y = LinearHelpers.validate_y_shape(y, n_samples, __MODULE__) - + opts = NimbleOptions.validate!(opts, @opts_schema) opts = @@ -158,7 +158,7 @@ defmodule Scholar.Linear.IsotonicRegression do {sample_weights, opts} = Keyword.pop(opts, :sample_weights, 1.0) x_type = to_float_type(x) x = to_float(x) - + y = to_float(y) sample_weights = diff --git a/test/scholar/linear/isotonic_regression_test.exs b/test/scholar/linear/isotonic_regression_test.exs index bd4bf9d3..74290d2d 100644 --- a/test/scholar/linear/isotonic_regression_test.exs +++ b/test/scholar/linear/isotonic_regression_test.exs @@ -96,9 +96,8 @@ defmodule Scholar.Linear.IsotonicRegressionTest do y = Nx.tensor([2.0, 3.0, 7.0, 8.0, 9.0]) sample_weights = Nx.tensor([1, 3, 2, 7, 4]) model = IsotonicRegression.fit(x, y, sample_weights: sample_weights) - col_model = IsotonicRegression.fit(x, y |> Nx.new_axis(-1), - sample_weights: sample_weights) - assert model == col_model + col_model = IsotonicRegression.fit(x, y |> Nx.new_axis(-1), sample_weights: sample_weights) + assert model == col_model end test "fit 2 column target raises" do @@ -107,13 +106,15 @@ defmodule Scholar.Linear.IsotonicRegressionTest do y = Nx.new_axis(y, -1) y = Nx.concatenate([y, y], axis: 1) sample_weights = Nx.tensor([1, 3, 2, 7, 4]) + message = "Elixir.#{inspect(IsotonicRegression)} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" assert_raise ArgumentError, message, fn -> - IsotonicRegression.fit(x, y, sample_weights: sample_weights) end + IsotonicRegression.fit(x, y, sample_weights: sample_weights) + end end test "fit with sample_weights and :increasing? set to false" do diff --git a/test/scholar/linear/svm_test.exs b/test/scholar/linear/svm_test.exs index d237522f..16bcf02d 100644 --- a/test/scholar/linear/svm_test.exs +++ b/test/scholar/linear/svm_test.exs @@ -44,6 +44,7 @@ defmodule Scholar.Linear.SVMTest do end y_train = Nx.new_axis(y_train, -1) + y_train = Nx.concatenate([y_train, y_train], axis: 1) From b5abefa84e66c058e1b85e925ff405065631f557 Mon Sep 17 00:00:00 2001 From: joaquin Date: Mon, 1 Jul 2024 18:14:12 +0200 Subject: [PATCH 15/33] decouple validation from flattening helper to handle multioutput options --- lib/scholar/linear/linear_helpers.ex | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index 315adcb5..2a4be4a9 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -5,10 +5,25 @@ defmodule Scholar.Linear.LinearHelpers do @moduledoc false + @doc false + def valid_column_vector(y, n_samples) do + (Nx.shape(y) == {n_samples, 1}) and (Nx.rank(y) == 2) + end + + @doc false + def flatten_column_vector(y, n_samples) do + is_column_vector? = valid_column_vector(y, n_samples) + if is_column_vector? do + y |> Nx.flatten() + else + y + end + end + @doc false def validate_y_shape(y, n_samples, module_name) do - is_column_vector? = Nx.shape(y) == {n_samples, 1} and Nx.rank(y) == 2 - is_valid_target? = Nx.rank(y) == 1 or is_column_vector? + y = flatten_column_vector(y, n_samples) + is_valid_target? = Nx.rank(y) == 1 if not is_valid_target? do message = @@ -16,7 +31,7 @@ defmodule Scholar.Linear.LinearHelpers do raise ArgumentError, message else - y |> Nx.flatten() + y end end From 45eab771ae637b9a46cd48ee80c03f9a48cdcfc3 Mon Sep 17 00:00:00 2001 From: joaquin Date: Mon, 1 Jul 2024 18:14:49 +0200 Subject: [PATCH 16/33] flatten linear input. no longer matches sklearn --- lib/scholar/linear/linear_regression.ex | 4 +++ .../scholar/linear/linear_regression_test.exs | 31 +++++++++---------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/lib/scholar/linear/linear_regression.ex b/lib/scholar/linear/linear_regression.ex index 761fced0..47d4e0d2 100644 --- a/lib/scholar/linear/linear_regression.ex +++ b/lib/scholar/linear/linear_regression.ex @@ -68,6 +68,8 @@ defmodule Scholar.Linear.LinearRegression do > """ deftransform fit(x, y, opts \\ []) do + {n_samples, _} = Nx.shape(x) + y = LinearHelpers.flatten_column_vector(y, n_samples) opts = NimbleOptions.validate!(opts, @opts_schema) opts = @@ -77,6 +79,8 @@ defmodule Scholar.Linear.LinearRegression do opts sample_weights = LinearHelpers.build_sample_weights(x, opts) + {n_samples, _} = Nx.shape(x) + y = LinearHelpers.flatten_column_vector(y, n_samples) fit_n(x, y, sample_weights, opts) end diff --git a/test/scholar/linear/linear_regression_test.exs b/test/scholar/linear/linear_regression_test.exs index 319c9339..9aff2797 100644 --- a/test/scholar/linear/linear_regression_test.exs +++ b/test/scholar/linear/linear_regression_test.exs @@ -4,10 +4,10 @@ defmodule Scholar.Linear.LinearRegressionTest do doctest LinearRegression describe "fit" do - test "matches sklearn for shapes {1, 1}, {1, 1} and type {:f, 32}" do + test "test for shapes {1, 1}, {1, 1} and type {:f, 32}" do a = Nx.tensor([[0.5666993856430054]]) b = Nx.tensor([[0.8904717564582825]]) - expected_coeff = Nx.tensor([[0.0]]) + expected_coeff = Nx.tensor([0.0]) expected_intercept = Nx.tensor([0.89047176]) %LinearRegression{coefficients: actual_coeff, intercept: actual_intercept} = @@ -17,7 +17,7 @@ defmodule Scholar.Linear.LinearRegressionTest do assert_all_close(expected_intercept, actual_intercept) end - test "matches sklearn for shapes {4, 6}, {4} and type {:f, 32}" do + test "test for shapes {4, 6}, {4} and type {:f, 32}" do a = Nx.tensor([ [ @@ -76,7 +76,7 @@ defmodule Scholar.Linear.LinearRegressionTest do assert_all_close(expected_intercept, actual_intercept, rtol: 1.0e-2, atol: 1.0e-3) end - test "matches sklearn for shapes {6, 6}, {6, 1} and type {:f, 64}" do + test "test for shapes {6, 6}, {6, 1} and type {:f, 64}" do a = Nx.tensor([ [ @@ -141,14 +141,12 @@ defmodule Scholar.Linear.LinearRegressionTest do expected_coeff = Nx.tensor([ - [ -0.3777002030151436, -0.4445957357428203, -0.14451413829286042, 0.31438593891571714, -0.9484560114249797, 0.04914973264178196 - ] ]) expected_intercept = Nx.tensor([1.31901913]) @@ -160,7 +158,7 @@ defmodule Scholar.Linear.LinearRegressionTest do assert_all_close(expected_intercept, actual_intercept, rtol: 1.0e-2, atol: 1.0e-3) end - test "matches sklearn for shapes {8, 6}, {8, 4} and type {:f, 32}" do + test "test for shapes {8, 6}, {8, 4} and type {:f, 32}" do a = Nx.tensor([ [ @@ -286,11 +284,11 @@ defmodule Scholar.Linear.LinearRegressionTest do assert_all_close(expected_intercept, actual_intercept, rtol: 1.0e-1, atol: 1.0e-2) end - test "matches sklearn for shapes {1, 1}, {1, 1} and type {:f, 32} and sample_weights" do + test "test for shapes {1, 1}, {1, 1} and type {:f, 32} and sample_weights" do a = Nx.tensor([[0.3166404366493225]]) b = Nx.tensor([[0.6253954172134399]]) sample_weights = [0.2065236121416092] - expected_coeff = Nx.tensor([[0.0]]) + expected_coeff = Nx.tensor([0.0]) expected_intercept = Nx.tensor([0.62539542]) %LinearRegression{coefficients: actual_coeff, intercept: actual_intercept} = @@ -364,7 +362,7 @@ defmodule Scholar.Linear.LinearRegressionTest do assert_all_close(expected_intercept, actual_intercept, rtol: 1.0e-3, atol: 1.0e-2) end - test "matches sklearn for shapes {6, 6}, {6, 1} and type {:f, 64} and sample_weight" do + test "test for shapes {6, 6}, {6, 1} and type {:f, 64} and sample_weight" do a = Nx.tensor([ [ @@ -437,7 +435,7 @@ defmodule Scholar.Linear.LinearRegressionTest do ] expected_coeff = - Nx.tensor([[-1.252728, 0.33221864, -0.23523702, -0.53585187, 0.00157968, -0.24489391]]) + Nx.tensor([-1.252728, 0.33221864, -0.23523702, -0.53585187, 0.00157968, -0.24489391]) expected_intercept = Nx.tensor([1.52024138]) @@ -448,7 +446,7 @@ defmodule Scholar.Linear.LinearRegressionTest do assert_all_close(expected_intercept, actual_intercept, rtol: 1.0e-2, atol: 1.0e-3) end - test "matches sklearn for shapes {8, 6}, {8, 4} and type {:f, 32} and sample_weight" do + test "test for shapes {8, 6}, {8, 4} and type {:f, 32} and sample_weight" do a = Nx.tensor([ [ @@ -900,12 +898,11 @@ defmodule Scholar.Linear.LinearRegressionTest do @tag :wip test "test column target" do x = Nx.tensor([[1], [2], [6], [8], [10]]) - y = Nx.tensor([1, 2, 6, 8, 10]) |> Nx.new_axis(-1) + y = Nx.tensor([1, 2, 6, 8, 10]) + lr = LinearRegression.fit(x, y) - test = Nx.tensor([[1], [3], [4]]) - expected = Nx.tensor([1, 3, 4]) |> Nx.new_axis(-1) - predicted = LinearRegression.predict(lr, test) - assert_all_close(expected, predicted, atol: 1.0e-1) + lr_column = LinearRegression.fit(x, y |> Nx.new_axis(-1)) + assert lr == lr_column end end end From 4d4aff19a2ae05ab99142a30c55885f23426683d Mon Sep 17 00:00:00 2001 From: joaquin Date: Mon, 1 Jul 2024 18:16:20 +0200 Subject: [PATCH 17/33] add prediction test --- test/scholar/linear/linear_regression_test.exs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/scholar/linear/linear_regression_test.exs b/test/scholar/linear/linear_regression_test.exs index 9aff2797..c2e65cb1 100644 --- a/test/scholar/linear/linear_regression_test.exs +++ b/test/scholar/linear/linear_regression_test.exs @@ -902,7 +902,10 @@ defmodule Scholar.Linear.LinearRegressionTest do lr = LinearRegression.fit(x, y) lr_column = LinearRegression.fit(x, y |> Nx.new_axis(-1)) + pred = LinearRegression.predict(lr, x) + pred_col = LinearRegression.predict(lr_column, x) assert lr == lr_column + assert pred == pred_col end end end From 455e6b0bc914932a2a6ac61bf63f3d394caf06e6 Mon Sep 17 00:00:00 2001 From: joaquin Date: Mon, 1 Jul 2024 18:24:07 +0200 Subject: [PATCH 18/33] linear regression always returns {n_samples} vector --- lib/scholar/linear/isotonic_regression.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scholar/linear/isotonic_regression.ex b/lib/scholar/linear/isotonic_regression.ex index 317453ca..21701b3d 100644 --- a/lib/scholar/linear/isotonic_regression.ex +++ b/lib/scholar/linear/isotonic_regression.ex @@ -525,6 +525,6 @@ defmodule Scholar.Linear.IsotonicRegression do x = Nx.new_axis(x, -1) y = Nx.new_axis(y, -1) model = Scholar.Linear.LinearRegression.fit(x, y) - model.coefficients[0][0] >= 0 + model.coefficients[0] >= 0 end end From 95b882551dc762d1ae0d02aae4c5248f2a6fdbee Mon Sep 17 00:00:00 2001 From: joaquin Date: Wed, 10 Jul 2024 19:37:09 +0200 Subject: [PATCH 19/33] formatter --- lib/scholar/linear/linear_helpers.ex | 7 ++++--- test/scholar/linear/linear_regression_test.exs | 14 +++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index 2a4be4a9..e5418f34 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -7,12 +7,13 @@ defmodule Scholar.Linear.LinearHelpers do @doc false def valid_column_vector(y, n_samples) do - (Nx.shape(y) == {n_samples, 1}) and (Nx.rank(y) == 2) + Nx.shape(y) == {n_samples, 1} and Nx.rank(y) == 2 end - + @doc false def flatten_column_vector(y, n_samples) do is_column_vector? = valid_column_vector(y, n_samples) + if is_column_vector? do y |> Nx.flatten() else @@ -23,7 +24,7 @@ defmodule Scholar.Linear.LinearHelpers do @doc false def validate_y_shape(y, n_samples, module_name) do y = flatten_column_vector(y, n_samples) - is_valid_target? = Nx.rank(y) == 1 + is_valid_target? = Nx.rank(y) == 1 if not is_valid_target? do message = diff --git a/test/scholar/linear/linear_regression_test.exs b/test/scholar/linear/linear_regression_test.exs index c2e65cb1..5ea28509 100644 --- a/test/scholar/linear/linear_regression_test.exs +++ b/test/scholar/linear/linear_regression_test.exs @@ -141,12 +141,12 @@ defmodule Scholar.Linear.LinearRegressionTest do expected_coeff = Nx.tensor([ - -0.3777002030151436, - -0.4445957357428203, - -0.14451413829286042, - 0.31438593891571714, - -0.9484560114249797, - 0.04914973264178196 + -0.3777002030151436, + -0.4445957357428203, + -0.14451413829286042, + 0.31438593891571714, + -0.9484560114249797, + 0.04914973264178196 ]) expected_intercept = Nx.tensor([1.31901913]) @@ -899,7 +899,7 @@ defmodule Scholar.Linear.LinearRegressionTest do test "test column target" do x = Nx.tensor([[1], [2], [6], [8], [10]]) y = Nx.tensor([1, 2, 6, 8, 10]) - + lr = LinearRegression.fit(x, y) lr_column = LinearRegression.fit(x, y |> Nx.new_axis(-1)) pred = LinearRegression.predict(lr, x) From 149ead68618c36f6d37951dc4781a8b00b802822 Mon Sep 17 00:00:00 2001 From: joaquin Date: Wed, 10 Jul 2024 19:37:23 +0200 Subject: [PATCH 20/33] bayesian ridge fixed --- .../linear/bayesian_ridge_regression.ex | 3 ++ .../linear/bayesian_ridge_regression_test.exs | 30 +++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/scholar/linear/bayesian_ridge_regression.ex b/lib/scholar/linear/bayesian_ridge_regression.ex index 8af3b8fe..3daab832 100644 --- a/lib/scholar/linear/bayesian_ridge_regression.ex +++ b/lib/scholar/linear/bayesian_ridge_regression.ex @@ -224,6 +224,9 @@ defmodule Scholar.Linear.BayesianRidgeRegression do > """ deftransform fit(x, y, opts \\ []) do + {n_samples, _} = Nx.shape(x) + y = LinearHelpers.validate_y_shape(y, n_samples, __MODULE__) + opts = NimbleOptions.validate!(opts, @opts_schema) opts = diff --git a/test/scholar/linear/bayesian_ridge_regression_test.exs b/test/scholar/linear/bayesian_ridge_regression_test.exs index 119e3fec..64d9f100 100644 --- a/test/scholar/linear/bayesian_ridge_regression_test.exs +++ b/test/scholar/linear/bayesian_ridge_regression_test.exs @@ -18,12 +18,30 @@ defmodule Scholar.Linear.BayesianRidgeRegressionTest do @tag :wip test "toy bayesian ridge with column target" do x = Nx.tensor([[1], [2], [6], [8], [10]]) - y = Nx.tensor([1, 2, 6, 8, 10]) |> Nx.new_axis(-1) - clf = BayesianRidgeRegression.fit(x, y) - test = Nx.tensor([[1], [3], [4]]) - expected = Nx.tensor([1, 3, 4]) |> Nx.new_axis(-1) - predicted = BayesianRidgeRegression.predict(clf, test) - assert_all_close(expected, predicted, atol: 1.0e-1) + y = Nx.tensor([1, 2, 6, 8, 10]) + model = BayesianRidgeRegression.fit(x, y) + pred = BayesianRidgeRegression.predict(model, x) + col_model = BayesianRidgeRegression.fit(x, y |> Nx.new_axis(-1)) + col_pred = BayesianRidgeRegression.predict(col_model, x) + assert model == col_model + assert pred == col_pred + end + + @tag :wip + test "2 column target raises" do + x = Nx.tensor([[1], [2], [6], [8], [10]]) + y = Nx.tensor([1, 2, 6, 8, 10]) + y = Nx.new_axis(y, -1) + y = Nx.concatenate([y, y], axis: 1) + + message = + "Elixir.#{inspect(BayesianRidgeRegression)} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + + assert_raise ArgumentError, + message, + fn -> + BayesianRidgeRegression.fit(x, y) + end end test "ridge vs bayesian ridge: parameters" do From 7af987c12ef3f89b19483a743c5dd957acddc547 Mon Sep 17 00:00:00 2001 From: joaquin Date: Wed, 10 Jul 2024 19:38:03 +0200 Subject: [PATCH 21/33] remove wip tags --- test/scholar/linear/bayesian_ridge_regression_test.exs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/scholar/linear/bayesian_ridge_regression_test.exs b/test/scholar/linear/bayesian_ridge_regression_test.exs index 64d9f100..0766d61f 100644 --- a/test/scholar/linear/bayesian_ridge_regression_test.exs +++ b/test/scholar/linear/bayesian_ridge_regression_test.exs @@ -15,7 +15,6 @@ defmodule Scholar.Linear.BayesianRidgeRegressionTest do assert_all_close(expected, predicted, atol: 1.0e-1) end - @tag :wip test "toy bayesian ridge with column target" do x = Nx.tensor([[1], [2], [6], [8], [10]]) y = Nx.tensor([1, 2, 6, 8, 10]) @@ -27,7 +26,6 @@ defmodule Scholar.Linear.BayesianRidgeRegressionTest do assert pred == col_pred end - @tag :wip test "2 column target raises" do x = Nx.tensor([[1], [2], [6], [8], [10]]) y = Nx.tensor([1, 2, 6, 8, 10]) From 086595092ca916ac19e9295f6717a4b65222e781 Mon Sep 17 00:00:00 2001 From: joaquin Date: Wed, 10 Jul 2024 19:38:43 +0200 Subject: [PATCH 22/33] removing wip tags --- test/scholar/linear/linear_regression_test.exs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/scholar/linear/linear_regression_test.exs b/test/scholar/linear/linear_regression_test.exs index 5ea28509..873d60e9 100644 --- a/test/scholar/linear/linear_regression_test.exs +++ b/test/scholar/linear/linear_regression_test.exs @@ -895,7 +895,6 @@ defmodule Scholar.Linear.LinearRegressionTest do end describe "fit and predict with colum target" do - @tag :wip test "test column target" do x = Nx.tensor([[1], [2], [6], [8], [10]]) y = Nx.tensor([1, 2, 6, 8, 10]) From d972a52691b015b2fe073048071b61aeebe80307 Mon Sep 17 00:00:00 2001 From: joaquin Date: Wed, 10 Jul 2024 19:49:58 +0200 Subject: [PATCH 23/33] refactor test data --- .../linear/polynomial_regression_test.exs | 60 ++++--------------- 1 file changed, 13 insertions(+), 47 deletions(-) diff --git a/test/scholar/linear/polynomial_regression_test.exs b/test/scholar/linear/polynomial_regression_test.exs index 1a348d72..b1aa4f85 100644 --- a/test/scholar/linear/polynomial_regression_test.exs +++ b/test/scholar/linear/polynomial_regression_test.exs @@ -66,9 +66,7 @@ defmodule Scholar.Linear.PolynomialRegressionTest do end end - describe "predict" do - test "predict when :fit_intercept? set to true, degree set to 2" do - a = + def a do Nx.tensor([ [ 0.7731901407241821, @@ -103,14 +101,23 @@ defmodule Scholar.Linear.PolynomialRegressionTest do 0.9986271858215332 ] ]) + + end - b = + def b do Nx.tensor([ 0.38682249188423157, 0.8040792346000671, 0.8069542646408081, 0.3620224595069885 ]) + end + + describe "predict" do + test "predict when :fit_intercept? set to true, degree set to 2" do + a = a() + + b = b() sample_weights = [ 0.8669093251228333, @@ -134,49 +141,8 @@ defmodule Scholar.Linear.PolynomialRegressionTest do end test "predict when :fit_intercept? set to false, degree set to 3" do - a = - Nx.tensor([ - [ - 0.7731901407241821, - 0.5813425779342651, - 0.8365984559059143, - 0.2182593196630478, - 0.06448899209499359, - 0.9420031905174255 - ], - [ - 0.6547101736068726, - 0.05023770406842232, - 0.657528281211853, - 0.24924135208129883, - 0.8238568902015686, - 0.11182288080453873 - ], - [ - 0.7693489193916321, - 0.6696648001670837, - 0.6877049803733826, - 0.08740159869194031, - 0.6053816676139832, - 0.5419610142707825 - ], - [ - 0.03419172018766403, - 0.8298202753067017, - 0.6097439527511597, - 0.0184243805706501, - 0.5578944087028503, - 0.9986271858215332 - ] - ]) - - b = - Nx.tensor([ - 0.38682249188423157, - 0.8040792346000671, - 0.8069542646408081, - 0.3620224595069885 - ]) + a = a() + b = b() sample_weights = [ 0.8669093251228333, From c555ec9a487f99355b6ba8cb4878990ed68a35a0 Mon Sep 17 00:00:00 2001 From: joaquin Date: Wed, 10 Jul 2024 20:01:29 +0200 Subject: [PATCH 24/33] wrote polynomial regression test --- .../linear/polynomial_regression_test.exs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/scholar/linear/polynomial_regression_test.exs b/test/scholar/linear/polynomial_regression_test.exs index b1aa4f85..50367b5a 100644 --- a/test/scholar/linear/polynomial_regression_test.exs +++ b/test/scholar/linear/polynomial_regression_test.exs @@ -264,4 +264,34 @@ defmodule Scholar.Linear.PolynomialRegressionTest do expected end end + + describe "column target tests" do + test "fit column target" do + a = a() + b = b() + + sample_weights = [ + 0.8669093251228333, + 0.10421276837587357, + 0.996828556060791, + 0.29747673869132996 + ] + + prediction_input = Nx.tensor([[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]]) + model = PolynomialRegression.fit(a, b, + degree: 2, + sample_weights: sample_weights, + fit_intercept?: true + ) + prediction = PolynomialRegression.predict(model, prediction_input) + col_model = PolynomialRegression.fit(a, b |> Nx.new_axis(-1), + degree: 2, + sample_weights: sample_weights, + fit_intercept?: true + ) + col_prediction = PolynomialRegression.predict(col_model, prediction_input) + assert model == col_model + assert prediction == col_prediction + end + end end From 4d334d399834bb6be281fddcd974b154ac87e9a3 Mon Sep 17 00:00:00 2001 From: joaquin Date: Wed, 10 Jul 2024 20:01:42 +0200 Subject: [PATCH 25/33] wrote tests for logistic and ridge regression --- test/scholar/linear/logistic_regression_test.exs | 15 +++++++++++++++ test/scholar/linear/ridge_regression_test.exs | 12 ++++++++++++ 2 files changed, 27 insertions(+) diff --git a/test/scholar/linear/logistic_regression_test.exs b/test/scholar/linear/logistic_regression_test.exs index 549d25d3..62191969 100644 --- a/test/scholar/linear/logistic_regression_test.exs +++ b/test/scholar/linear/logistic_regression_test.exs @@ -83,4 +83,19 @@ defmodule Scholar.Linear.LogisticRegressionTest do fn -> LogisticRegression.fit(x, y, num_classes: 2) end end end + + describe "column target tests" do + @tag :wip + test "column target" do + {x_train, _, y_train, _} = iris_data() + + model = LogisticRegression.fit(x_train, y_train, num_classes: 3) + pred = LogisticRegression.predict(model, x_train) + col_model = LogisticRegression.fit(x_train, y_train |> Nx.new_axis(-1), + num_classes: 3) + col_pred = LogisticRegression.predict(col_model, x_train) + assert model == col_model + assert pred == col_pred + end + end end diff --git a/test/scholar/linear/ridge_regression_test.exs b/test/scholar/linear/ridge_regression_test.exs index a4f8e9df..66717a9b 100644 --- a/test/scholar/linear/ridge_regression_test.exs +++ b/test/scholar/linear/ridge_regression_test.exs @@ -281,4 +281,16 @@ defmodule Scholar.Linear.RidgeRegressionTest do assert_all_close(expected_prediction, actual_prediction) end end + + @tag :wip + test "toy ridge with column target" do + x = Nx.tensor([[1], [2], [6], [8], [10]]) + y = Nx.tensor([1, 2, 6, 8, 10]) + model = RidgeRegression.fit(x, y) + pred = RidgeRegression.predict(model, x) + col_model = RidgeRegression.fit(x, y |> Nx.new_axis(-1)) + col_pred = RidgeRegression.predict(col_model, x) + assert model == col_model + assert pred == col_pred + end end From 27e8cc6f2c942b49812e2dbb35a6086fb7985fd9 Mon Sep 17 00:00:00 2001 From: joaquin Date: Wed, 10 Jul 2024 20:07:53 +0200 Subject: [PATCH 26/33] logistic and ridge test pass --- lib/scholar/linear/logistic_regression.ex | 7 +- lib/scholar/linear/ridge_regression.ex | 3 + .../linear/logistic_regression_test.exs | 5 +- .../linear/polynomial_regression_test.exs | 91 ++++++++++--------- 4 files changed, 56 insertions(+), 50 deletions(-) diff --git a/lib/scholar/linear/logistic_regression.ex b/lib/scholar/linear/logistic_regression.ex index 3c62c9fa..7f8fbce1 100644 --- a/lib/scholar/linear/logistic_regression.ex +++ b/lib/scholar/linear/logistic_regression.ex @@ -6,6 +6,7 @@ defmodule Scholar.Linear.LogisticRegression do """ import Nx.Defn import Scholar.Shared + alias Scholar.Linear.LinearHelpers @derive {Nx.Container, containers: [:coefficients, :bias]} defstruct [:coefficients, :bias] @@ -94,10 +95,8 @@ defmodule Scholar.Linear.LogisticRegression do "expected x to have shape {n_samples, n_features}, got tensor with shape: #{inspect(Nx.shape(x))}" end - if Nx.rank(y) != 1 do - raise ArgumentError, - "expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" - end + {n_samples, _} = Nx.shape(x) + y = LinearHelpers.validate_y_shape(y, n_samples, __MODULE__) opts = NimbleOptions.validate!(opts, @opts_schema) diff --git a/lib/scholar/linear/ridge_regression.ex b/lib/scholar/linear/ridge_regression.ex index 70bed1c6..409b5d16 100644 --- a/lib/scholar/linear/ridge_regression.ex +++ b/lib/scholar/linear/ridge_regression.ex @@ -109,6 +109,9 @@ defmodule Scholar.Linear.RidgeRegression do } """ deftransform fit(x, y, opts \\ []) do + {n_samples, _} = Nx.shape(x) + y = LinearHelpers.flatten_column_vector(y, n_samples) + opts = NimbleOptions.validate!(opts, @opts_schema) sample_weights? = opts[:sample_weights] != nil diff --git a/test/scholar/linear/logistic_regression_test.exs b/test/scholar/linear/logistic_regression_test.exs index 62191969..6c64e5c7 100644 --- a/test/scholar/linear/logistic_regression_test.exs +++ b/test/scholar/linear/logistic_regression_test.exs @@ -79,7 +79,7 @@ defmodule Scholar.Linear.LogisticRegressionTest do y = Nx.tensor([[0, 1], [1, 0]]) assert_raise ArgumentError, - "expected y to have shape {n_samples}, got tensor with shape: {2, 2}", + "Elixir.#{inspect(LogisticRegression)} expected y to have shape {n_samples}, got tensor with shape: {2, 2}", fn -> LogisticRegression.fit(x, y, num_classes: 2) end end end @@ -91,8 +91,7 @@ defmodule Scholar.Linear.LogisticRegressionTest do model = LogisticRegression.fit(x_train, y_train, num_classes: 3) pred = LogisticRegression.predict(model, x_train) - col_model = LogisticRegression.fit(x_train, y_train |> Nx.new_axis(-1), - num_classes: 3) + col_model = LogisticRegression.fit(x_train, y_train |> Nx.new_axis(-1), num_classes: 3) col_pred = LogisticRegression.predict(col_model, x_train) assert model == col_model assert pred == col_pred diff --git a/test/scholar/linear/polynomial_regression_test.exs b/test/scholar/linear/polynomial_regression_test.exs index 50367b5a..295a6760 100644 --- a/test/scholar/linear/polynomial_regression_test.exs +++ b/test/scholar/linear/polynomial_regression_test.exs @@ -67,50 +67,49 @@ defmodule Scholar.Linear.PolynomialRegressionTest do end def a do - Nx.tensor([ - [ - 0.7731901407241821, - 0.5813425779342651, - 0.8365984559059143, - 0.2182593196630478, - 0.06448899209499359, - 0.9420031905174255 - ], - [ - 0.6547101736068726, - 0.05023770406842232, - 0.657528281211853, - 0.24924135208129883, - 0.8238568902015686, - 0.11182288080453873 - ], - [ - 0.7693489193916321, - 0.6696648001670837, - 0.6877049803733826, - 0.08740159869194031, - 0.6053816676139832, - 0.5419610142707825 - ], - [ - 0.03419172018766403, - 0.8298202753067017, - 0.6097439527511597, - 0.0184243805706501, - 0.5578944087028503, - 0.9986271858215332 - ] - ]) - + Nx.tensor([ + [ + 0.7731901407241821, + 0.5813425779342651, + 0.8365984559059143, + 0.2182593196630478, + 0.06448899209499359, + 0.9420031905174255 + ], + [ + 0.6547101736068726, + 0.05023770406842232, + 0.657528281211853, + 0.24924135208129883, + 0.8238568902015686, + 0.11182288080453873 + ], + [ + 0.7693489193916321, + 0.6696648001670837, + 0.6877049803733826, + 0.08740159869194031, + 0.6053816676139832, + 0.5419610142707825 + ], + [ + 0.03419172018766403, + 0.8298202753067017, + 0.6097439527511597, + 0.0184243805706501, + 0.5578944087028503, + 0.9986271858215332 + ] + ]) end def b do - Nx.tensor([ - 0.38682249188423157, - 0.8040792346000671, - 0.8069542646408081, - 0.3620224595069885 - ]) + Nx.tensor([ + 0.38682249188423157, + 0.8040792346000671, + 0.8069542646408081, + 0.3620224595069885 + ]) end describe "predict" do @@ -278,17 +277,23 @@ defmodule Scholar.Linear.PolynomialRegressionTest do ] prediction_input = Nx.tensor([[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]]) - model = PolynomialRegression.fit(a, b, + + model = + PolynomialRegression.fit(a, b, degree: 2, sample_weights: sample_weights, fit_intercept?: true ) + prediction = PolynomialRegression.predict(model, prediction_input) - col_model = PolynomialRegression.fit(a, b |> Nx.new_axis(-1), + + col_model = + PolynomialRegression.fit(a, b |> Nx.new_axis(-1), degree: 2, sample_weights: sample_weights, fit_intercept?: true ) + col_prediction = PolynomialRegression.predict(col_model, prediction_input) assert model == col_model assert prediction == col_prediction From 55106de83fe6afe983ad31c5567f43602a6d642f Mon Sep 17 00:00:00 2001 From: JoaquinIglesiasTurina Date: Sun, 28 Jul 2024 10:42:07 +0200 Subject: [PATCH 27/33] Update lib/scholar/linear/linear_helpers.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/scholar/linear/linear_helpers.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index e5418f34..ef4caa4b 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -28,7 +28,7 @@ defmodule Scholar.Linear.LinearHelpers do if not is_valid_target? do message = - "#{module_name} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + "#{inspect(module_name)} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" raise ArgumentError, message else From bde15516f8dc896042e3e5e8e7c5773706f72d68 Mon Sep 17 00:00:00 2001 From: JoaquinIglesiasTurina Date: Sun, 28 Jul 2024 10:42:14 +0200 Subject: [PATCH 28/33] Update lib/scholar/linear/linear_helpers.ex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/scholar/linear/linear_helpers.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index ef4caa4b..f6402292 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -5,8 +5,7 @@ defmodule Scholar.Linear.LinearHelpers do @moduledoc false - @doc false - def valid_column_vector(y, n_samples) do + defp valid_column_vector?(y, n_samples) do Nx.shape(y) == {n_samples, 1} and Nx.rank(y) == 2 end From 348e171804ba625bc38033e639016ad2a5973b45 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 28 Jul 2024 11:07:53 +0200 Subject: [PATCH 29/33] fixed valid_colum_vector? name --- lib/scholar/linear/linear_helpers.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scholar/linear/linear_helpers.ex b/lib/scholar/linear/linear_helpers.ex index f6402292..315d7b51 100644 --- a/lib/scholar/linear/linear_helpers.ex +++ b/lib/scholar/linear/linear_helpers.ex @@ -11,7 +11,7 @@ defmodule Scholar.Linear.LinearHelpers do @doc false def flatten_column_vector(y, n_samples) do - is_column_vector? = valid_column_vector(y, n_samples) + is_column_vector? = valid_column_vector?(y, n_samples) if is_column_vector? do y |> Nx.flatten() From 0546cb3371a44924737a6268c30d2c8218ec3450 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 28 Jul 2024 11:08:21 +0200 Subject: [PATCH 30/33] fixed error messages --- test/scholar/linear/bayesian_ridge_regression_test.exs | 2 +- test/scholar/linear/isotonic_regression_test.exs | 2 +- test/scholar/linear/logistic_regression_test.exs | 2 +- test/scholar/linear/svm_test.exs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/scholar/linear/bayesian_ridge_regression_test.exs b/test/scholar/linear/bayesian_ridge_regression_test.exs index 0766d61f..c8dd6945 100644 --- a/test/scholar/linear/bayesian_ridge_regression_test.exs +++ b/test/scholar/linear/bayesian_ridge_regression_test.exs @@ -33,7 +33,7 @@ defmodule Scholar.Linear.BayesianRidgeRegressionTest do y = Nx.concatenate([y, y], axis: 1) message = - "Elixir.#{inspect(BayesianRidgeRegression)} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + "Scholar.Linear.BayesianRidgeRegression expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" assert_raise ArgumentError, message, diff --git a/test/scholar/linear/isotonic_regression_test.exs b/test/scholar/linear/isotonic_regression_test.exs index 74290d2d..568ff47b 100644 --- a/test/scholar/linear/isotonic_regression_test.exs +++ b/test/scholar/linear/isotonic_regression_test.exs @@ -108,7 +108,7 @@ defmodule Scholar.Linear.IsotonicRegressionTest do sample_weights = Nx.tensor([1, 3, 2, 7, 4]) message = - "Elixir.#{inspect(IsotonicRegression)} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" + "Scholar.Linear.IsotonicRegression expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y))}" assert_raise ArgumentError, message, diff --git a/test/scholar/linear/logistic_regression_test.exs b/test/scholar/linear/logistic_regression_test.exs index 6c64e5c7..8fc2d374 100644 --- a/test/scholar/linear/logistic_regression_test.exs +++ b/test/scholar/linear/logistic_regression_test.exs @@ -79,7 +79,7 @@ defmodule Scholar.Linear.LogisticRegressionTest do y = Nx.tensor([[0, 1], [1, 0]]) assert_raise ArgumentError, - "Elixir.#{inspect(LogisticRegression)} expected y to have shape {n_samples}, got tensor with shape: {2, 2}", + "Scholar.Linear.LogisticRegression expected y to have shape {n_samples}, got tensor with shape: {2, 2}", fn -> LogisticRegression.fit(x, y, num_classes: 2) end end end diff --git a/test/scholar/linear/svm_test.exs b/test/scholar/linear/svm_test.exs index 16bcf02d..0f643b1c 100644 --- a/test/scholar/linear/svm_test.exs +++ b/test/scholar/linear/svm_test.exs @@ -49,7 +49,7 @@ defmodule Scholar.Linear.SVMTest do Nx.concatenate([y_train, y_train], axis: 1) message = - "Elixir.#{inspect(SVM)} expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y_train))}" + "Scholar.Linear.SVM expected y to have shape {n_samples}, got tensor with shape: #{inspect(Nx.shape(y_train))}" assert_raise ArgumentError, message, From af993d7a72d7ae4585ecd7549efb21d544650a12 Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 28 Jul 2024 11:53:54 +0200 Subject: [PATCH 31/33] updated docs --- lib/scholar/linear/bayesian_ridge_regression.ex | 2 ++ lib/scholar/linear/isotonic_regression.ex | 2 ++ lib/scholar/linear/linear_regression.ex | 2 ++ lib/scholar/linear/logistic_regression.ex | 1 + lib/scholar/linear/polynomial_regression.ex | 2 ++ lib/scholar/linear/ridge_regression.ex | 2 ++ lib/scholar/linear/svm.ex | 1 + 7 files changed, 12 insertions(+) diff --git a/lib/scholar/linear/bayesian_ridge_regression.ex b/lib/scholar/linear/bayesian_ridge_regression.ex index 3daab832..fe6933f0 100644 --- a/lib/scholar/linear/bayesian_ridge_regression.ex +++ b/lib/scholar/linear/bayesian_ridge_regression.ex @@ -428,6 +428,8 @@ defmodule Scholar.Linear.BayesianRidgeRegression do @doc """ Makes predictions with the given `model` on input `x`. + Output predictions have shape {n_samples} when train target is shaped either {n_samples} or {n_samples, 1}. + ## Examples iex> x = Nx.tensor([[1], [2], [6], [8], [10]]) diff --git a/lib/scholar/linear/isotonic_regression.ex b/lib/scholar/linear/isotonic_regression.ex index 21701b3d..6ddd6d2e 100644 --- a/lib/scholar/linear/isotonic_regression.ex +++ b/lib/scholar/linear/isotonic_regression.ex @@ -201,6 +201,8 @@ defmodule Scholar.Linear.IsotonicRegression do @doc """ Makes predictions with the given `model` on input `x` and interpolating `function`. + Output predictions have shape {n_samples} when train target is shaped either {n_samples} or {n_samples, 1}. + Otherwise, predictions match train target shape. ## Examples diff --git a/lib/scholar/linear/linear_regression.ex b/lib/scholar/linear/linear_regression.ex index 47d4e0d2..4083033d 100644 --- a/lib/scholar/linear/linear_regression.ex +++ b/lib/scholar/linear/linear_regression.ex @@ -116,6 +116,8 @@ defmodule Scholar.Linear.LinearRegression do @doc """ Makes predictions with the given `model` on input `x`. + Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. + Otherwise, predictions match train target shape. ## Examples diff --git a/lib/scholar/linear/logistic_regression.ex b/lib/scholar/linear/logistic_regression.ex index 7f8fbce1..b2d972bb 100644 --- a/lib/scholar/linear/logistic_regression.ex +++ b/lib/scholar/linear/logistic_regression.ex @@ -203,6 +203,7 @@ defmodule Scholar.Linear.LogisticRegression do @doc """ Makes predictions with the given `model` on inputs `x`. + Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. ## Examples diff --git a/lib/scholar/linear/polynomial_regression.ex b/lib/scholar/linear/polynomial_regression.ex index 76246ad2..614a6ddf 100644 --- a/lib/scholar/linear/polynomial_regression.ex +++ b/lib/scholar/linear/polynomial_regression.ex @@ -109,6 +109,8 @@ defmodule Scholar.Linear.PolynomialRegression do @doc """ Makes predictions with the given `model` on input `x`. + Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. + Otherwise, predictions match train target shape. ## Examples diff --git a/lib/scholar/linear/ridge_regression.ex b/lib/scholar/linear/ridge_regression.ex index 409b5d16..d172a6c2 100644 --- a/lib/scholar/linear/ridge_regression.ex +++ b/lib/scholar/linear/ridge_regression.ex @@ -198,6 +198,8 @@ defmodule Scholar.Linear.RidgeRegression do @doc """ Makes predictions with the given `model` on input `x`. + Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. + Otherwise, predictions match train target shape. ## Examples diff --git a/lib/scholar/linear/svm.ex b/lib/scholar/linear/svm.ex index 8dddee20..10bd903e 100644 --- a/lib/scholar/linear/svm.ex +++ b/lib/scholar/linear/svm.ex @@ -250,6 +250,7 @@ defmodule Scholar.Linear.SVM do @doc """ Makes predictions with the given model on inputs `x`. + Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. ## Examples iex> x = Nx.tensor([[1.0, 2.0], [3.0, 2.0], [4.0, 7.0]]) From 88066fdc49c83c747886c30be67d9fdeec364c7d Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 28 Jul 2024 20:44:40 +0200 Subject: [PATCH 32/33] proper formatting of predict docs --- lib/scholar/linear/bayesian_ridge_regression.ex | 3 ++- lib/scholar/linear/isotonic_regression.ex | 3 ++- lib/scholar/linear/linear_regression.ex | 3 ++- lib/scholar/linear/logistic_regression.ex | 3 ++- lib/scholar/linear/polynomial_regression.ex | 3 ++- lib/scholar/linear/ridge_regression.ex | 3 ++- lib/scholar/linear/svm.ex | 3 ++- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/scholar/linear/bayesian_ridge_regression.ex b/lib/scholar/linear/bayesian_ridge_regression.ex index fe6933f0..d020431b 100644 --- a/lib/scholar/linear/bayesian_ridge_regression.ex +++ b/lib/scholar/linear/bayesian_ridge_regression.ex @@ -428,7 +428,8 @@ defmodule Scholar.Linear.BayesianRidgeRegression do @doc """ Makes predictions with the given `model` on input `x`. - Output predictions have shape {n_samples} when train target is shaped either {n_samples} or {n_samples, 1}. + + Output predictions have shape `{n_samples}` when train target is shaped either `{n_samples}` or `{n_samples, 1}`. ## Examples diff --git a/lib/scholar/linear/isotonic_regression.ex b/lib/scholar/linear/isotonic_regression.ex index 6ddd6d2e..d1ebf9af 100644 --- a/lib/scholar/linear/isotonic_regression.ex +++ b/lib/scholar/linear/isotonic_regression.ex @@ -201,7 +201,8 @@ defmodule Scholar.Linear.IsotonicRegression do @doc """ Makes predictions with the given `model` on input `x` and interpolating `function`. - Output predictions have shape {n_samples} when train target is shaped either {n_samples} or {n_samples, 1}. + + Output predictions have shape `{n_samples}` when train target is shaped either `{n_samples}` or `{n_samples, 1}`. Otherwise, predictions match train target shape. ## Examples diff --git a/lib/scholar/linear/linear_regression.ex b/lib/scholar/linear/linear_regression.ex index 4083033d..d40b9284 100644 --- a/lib/scholar/linear/linear_regression.ex +++ b/lib/scholar/linear/linear_regression.ex @@ -116,7 +116,8 @@ defmodule Scholar.Linear.LinearRegression do @doc """ Makes predictions with the given `model` on input `x`. - Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. + + Output predictions have shape `{n_samples}` when train target is shaped either `{n_samples}` or `{n_samples, 1}`. Otherwise, predictions match train target shape. ## Examples diff --git a/lib/scholar/linear/logistic_regression.ex b/lib/scholar/linear/logistic_regression.ex index b2d972bb..1530120d 100644 --- a/lib/scholar/linear/logistic_regression.ex +++ b/lib/scholar/linear/logistic_regression.ex @@ -203,7 +203,8 @@ defmodule Scholar.Linear.LogisticRegression do @doc """ Makes predictions with the given `model` on inputs `x`. - Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. + + Output predictions have shape `{n_samples}` when train target is shaped either `{n_samples}` or `{n_samples, 1}`. ## Examples diff --git a/lib/scholar/linear/polynomial_regression.ex b/lib/scholar/linear/polynomial_regression.ex index 614a6ddf..3df96bb0 100644 --- a/lib/scholar/linear/polynomial_regression.ex +++ b/lib/scholar/linear/polynomial_regression.ex @@ -109,7 +109,8 @@ defmodule Scholar.Linear.PolynomialRegression do @doc """ Makes predictions with the given `model` on input `x`. - Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. + + Output predictions have shape `{n_samples}` when train target is shaped either `{n_samples}` or `{n_samples, 1}`. Otherwise, predictions match train target shape. ## Examples diff --git a/lib/scholar/linear/ridge_regression.ex b/lib/scholar/linear/ridge_regression.ex index d172a6c2..95518ddf 100644 --- a/lib/scholar/linear/ridge_regression.ex +++ b/lib/scholar/linear/ridge_regression.ex @@ -198,7 +198,8 @@ defmodule Scholar.Linear.RidgeRegression do @doc """ Makes predictions with the given `model` on input `x`. - Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. + + Output predictions have shape `{n_samples}` when train target is shaped either `{n_samples}` or `{n_samples, 1}`. Otherwise, predictions match train target shape. ## Examples diff --git a/lib/scholar/linear/svm.ex b/lib/scholar/linear/svm.ex index 10bd903e..c8997bb0 100644 --- a/lib/scholar/linear/svm.ex +++ b/lib/scholar/linear/svm.ex @@ -250,7 +250,8 @@ defmodule Scholar.Linear.SVM do @doc """ Makes predictions with the given model on inputs `x`. - Output predictions have shape {n_samples}, when train target is shaped either {n_samples} or {n_samples, 1}. + + Output predictions have shape `{n_samples}` when train target is shaped either `{n_samples}` or `{n_samples, 1}`. ## Examples iex> x = Nx.tensor([[1.0, 2.0], [3.0, 2.0], [4.0, 7.0]]) From c22d40d723aa5cb070d8a3d8515b0d39d57d570a Mon Sep 17 00:00:00 2001 From: joaquin Date: Sun, 28 Jul 2024 20:46:01 +0200 Subject: [PATCH 33/33] ran formatter --- lib/scholar/linear/bayesian_ridge_regression.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scholar/linear/bayesian_ridge_regression.ex b/lib/scholar/linear/bayesian_ridge_regression.ex index d020431b..e98038c9 100644 --- a/lib/scholar/linear/bayesian_ridge_regression.ex +++ b/lib/scholar/linear/bayesian_ridge_regression.ex @@ -428,7 +428,7 @@ defmodule Scholar.Linear.BayesianRidgeRegression do @doc """ Makes predictions with the given `model` on input `x`. - + Output predictions have shape `{n_samples}` when train target is shaped either `{n_samples}` or `{n_samples, 1}`. ## Examples