From 97de7072369da139eddb7732b409e26982250740 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Tue, 10 Sep 2019 12:44:35 +1200 Subject: [PATCH 01/11] matching models to tasks draft --- src/model_matching.jl | 76 ++++++++++++++++++++++++++++++++++++++++++ test/model_matching.jl | 25 ++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/model_matching.jl create mode 100644 test/model_matching.jl diff --git a/src/model_matching.jl b/src/model_matching.jl new file mode 100644 index 000000000..bf5f48808 --- /dev/null +++ b/src/model_matching.jl @@ -0,0 +1,76 @@ +# Note. `ModelProxy` is the type of a model type's metadata entry (a +# named tuple). So, `info("PCA")` has this type, for example. + + +## BASIC IDEA + +if false + + matching(model::MLJModels.ModelProxy, X) = + !(model.is_supervised) && scitype(X) <: model.input_scitype + + matching(model::MLJModels.ModelProxy, X, y) = + model.is_supervised && + scitype(X) <: model.input_scitype && + scitype(y) <: model.target_scitype + + matching(model::MLJModels.ModelProxy, X, y, w::AbstractVector{<:Real}) = + model.is_supervised && + model.supports_weights && + scitype(X) <: model.input_scitype && + scitype(y) <: model.target_scitype + +end + +## IMPLEMENTATION + + + +struct ModelChecker{is_supervised, + supports_weights, + input_scitype, + target_scitype} end + +matching(X) = ModelChecker{false,false,scitype(X),missing}() +matching(X, y) = ModelChecker{true,false,scitype(X),scitype(y)}() +matching(X, y, w) = ModelChecker{true,true,scitype(X),scitype(y)}() + +(f::ModelChecker{false,false,XS})(model::MLJModels.ModelProxy) where XS = + !(model.is_supervised) && + XS <: model.input_scitype + +(f::ModelChecker{true,false,XS,yS})(model::MLJModels.ModelProxy) where {XS,yS} = + model.is_supervised && + XS <: model.input_scitype && + yS <: model.target_scitype + +(f::ModelChecker{true,false,XS,yS})(model::MLJModels.ModelProxy) where {XS,yS} = + model.is_supervised && + model.supports_weights && + XS <: model.input_scitype && + yS <: model.target_scitype + +(f::ModelChecker)(name::String; pkg=nothing) = f(info(name, pkg=pkg)) + +matching(model::MLJModels.ModelProxy, args...) = matching(args...)(model) +matching(name::String, args...; pkg=nothing) = + matching(info(name, pkg=pkg), args...) +matching(realmodel::Model, args...) = matching(info(realmodel), args...) + + +## DUAL NOTION + +struct DataChecker + model::MLJModels.ModelProxy +end + +matching(model::MLJModels.ModelProxy) = DataChecker(model) +matching(name::String; pkg=nothing) = DataChecker(info(name, pkg=pkg)) +matching(realmodel::Model) = matching(info(realmodel)) + +(f::DataChecker)(args...) = matching(f.model, args...) + + + + + diff --git a/test/model_matching.jl b/test/model_matching.jl new file mode 100644 index 000000000..a65957446 --- /dev/null +++ b/test/model_matching.jl @@ -0,0 +1,25 @@ +using MLJ +using Test + +X = (a = rand(5), b = categorical(1:5)) +y = rand(5) +w = rand(5) + +@test matching(X) == Main.ModelChecker{false,false,scitype(X),missing}() +@test matching(X, y) == Main.ModelChecker{true,false,scitype(X),scitype(y)}() +@test matching(X, y, w) == Main.ModelChecker{true,true,scitype(X),scitype(y)}() + +@test !matching("RidgeRegressor", pkg="MultivariateStats", X) +@test matching("FeatureSelector", X) + +m1 = models(matching(X)) +@test issubset([info("FeatureSelector"), + info("OneHotEncoder"), + info("Standardizer")], m1) + +@test !("PCA" in m1) +@test !(info("PCA") in m1) + +m2 = models(matching(X, y)) +matching(X, y)("ConstantRegressor") +matching(X,y) From aff919c046daabd5af2f429ecf08ee27e1d7a257 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Fri, 13 Sep 2019 11:26:10 +1200 Subject: [PATCH 02/11] first tested `matching` method --- src/MLJ.jl | 28 +++++++++++++++------------- src/model_matching.jl | 6 +++--- test/model_matching.jl | 11 ++++++++--- test/runtests.jl | 4 ++++ 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/MLJ.jl b/src/MLJ.jl index b2c0f125e..73b81d7ec 100644 --- a/src/MLJ.jl +++ b/src/MLJ.jl @@ -3,19 +3,20 @@ module MLJ ## EXPORTS # defined in include files: -export @curve, @pcurve, pretty, # utilities.jl - coerce, supervised, unsupervised, # tasks.jl - report, # machines.jl - Holdout, CV, evaluate!, Resampler, # resampling.jl - Params, params, set_params!, # parameters.jl - strange, iterator, # parameters.jl - Grid, TunedModel, learning_curve!, # tuning.jl - EnsembleModel, # ensembles.jl - rebind!, # networks.jl - machines, sources, anonymize!, # composites.jl - @from_network, # composites.jl - fitresults, # composites.jl - @pipeline # pipelines.jl +export @curve, @pcurve, pretty, # utilities.jl + coerce, supervised, unsupervised, # tasks.jl + report, # machines.jl + Holdout, CV, evaluate!, Resampler, # resampling.jl + Params, params, set_params!, # parameters.jl + strange, iterator, # parameters.jl + Grid, TunedModel, learning_curve!, # tuning.jl + EnsembleModel, # ensembles.jl + rebind!, # networks.jl + machines, sources, anonymize!, # composites.jl + @from_network, # composites.jl + fitresults, # composites.jl + @pipeline, # pipelines.jl + matching # matching.jl # defined in include files "machines.jl and "networks.jl": export Machine, NodalMachine, machine, AbstractNode, @@ -116,6 +117,7 @@ include("resampling.jl") # resampling strategies and model evaluation include("parameters.jl") # hyperparameter ranges and grid generation include("tuning.jl") include("ensembles.jl") # homogeneous ensembles +include("model_matching.jl")# inferring model search criterion from data include("tasks.jl") # enhancements to MLJBase task interface include("scitypes.jl") # extensions to ScientificTypes.sictype include("plotrecipes.jl") diff --git a/src/model_matching.jl b/src/model_matching.jl index bf5f48808..9af4ee182 100644 --- a/src/model_matching.jl +++ b/src/model_matching.jl @@ -1,5 +1,5 @@ -# Note. `ModelProxy` is the type of a model type's metadata entry (a -# named tuple). So, `info("PCA")` has this type, for example. +# Note. `ModelProxy` is the type of a model's metadata entry (a named +# tuple). So, `info("PCA")` has this type, for example. ## BASIC IDEA @@ -22,8 +22,8 @@ if false end -## IMPLEMENTATION +## IMPLEMENTATION struct ModelChecker{is_supervised, diff --git a/test/model_matching.jl b/test/model_matching.jl index a65957446..349e16294 100644 --- a/test/model_matching.jl +++ b/test/model_matching.jl @@ -1,3 +1,5 @@ +module TestMatching + using MLJ using Test @@ -5,9 +7,9 @@ X = (a = rand(5), b = categorical(1:5)) y = rand(5) w = rand(5) -@test matching(X) == Main.ModelChecker{false,false,scitype(X),missing}() -@test matching(X, y) == Main.ModelChecker{true,false,scitype(X),scitype(y)}() -@test matching(X, y, w) == Main.ModelChecker{true,true,scitype(X),scitype(y)}() +@test matching(X) == MLJ.ModelChecker{false,false,scitype(X),missing}() +@test matching(X, y) == MLJ.ModelChecker{true,false,scitype(X),scitype(y)}() +@test matching(X, y, w) == MLJ.ModelChecker{true,true,scitype(X),scitype(y)}() @test !matching("RidgeRegressor", pkg="MultivariateStats", X) @test matching("FeatureSelector", X) @@ -23,3 +25,6 @@ m1 = models(matching(X)) m2 = models(matching(X, y)) matching(X, y)("ConstantRegressor") matching(X,y) + +end +true diff --git a/test/runtests.jl b/test/runtests.jl index 10c0473e1..ab1799d79 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -45,6 +45,10 @@ end @test include("ensembles.jl") end +@testset "matching models to data" begin + @test include("model_matching.jl") +end + @testset "tasks" begin @test include("tasks.jl") end From d667443e66bee7a52bd7f763e2d5aa6b179e47e7 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Fri, 13 Sep 2019 12:14:04 +1200 Subject: [PATCH 03/11] fix wrong definition --- src/model_matching.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model_matching.jl b/src/model_matching.jl index 9af4ee182..71a315cc9 100644 --- a/src/model_matching.jl +++ b/src/model_matching.jl @@ -44,7 +44,7 @@ matching(X, y, w) = ModelChecker{true,true,scitype(X),scitype(y)}() XS <: model.input_scitype && yS <: model.target_scitype -(f::ModelChecker{true,false,XS,yS})(model::MLJModels.ModelProxy) where {XS,yS} = +(f::ModelChecker{true,true,XS,yS})(model::MLJModels.ModelProxy) where {XS,yS} = model.is_supervised && model.supports_weights && XS <: model.input_scitype && From 508ce08dd867eb98cde1573cb7ce4d68a4735632 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Fri, 13 Sep 2019 15:43:23 +1200 Subject: [PATCH 04/11] add test --- src/model_matching.jl | 38 ++++++++++++++++++++++++++++++++++++-- test/model_matching.jl | 6 +++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/model_matching.jl b/src/model_matching.jl index 71a315cc9..5305b9fee 100644 --- a/src/model_matching.jl +++ b/src/model_matching.jl @@ -29,13 +29,46 @@ end struct ModelChecker{is_supervised, supports_weights, input_scitype, - target_scitype} end + target_scitype} end + +function Base.getproperty(::ModelChecker{is_supervised, + supports_weights, + input_scitype, + target_scitype}, + field::Symbol) where {is_supervised, + supports_weights, + input_scitype, + target_scitype} + if field === :is_supervised + return is_supervised + elseif field === :supports_weights + return supports_weights + elseif field === :input_scitype + return input_scitype + elseif field === :target_scitype + return target_scitype + else + throw(ArgumentError("Unsupported property. ")) + end +end + +Base.propertynames(::ModelChecker) = + (:is_supervised, :supports_weights, :input_scitype, :target_scitype) + +function _as_named_tuple(s::ModelChecker) + names = propertynames(s) + NamedTuple{names}(Tuple(getproperty(s, p) for p in names)) +end + +# function Base.show(io::IO, ::MIME"text/plain", S::ModelChecker) +# show(io, MIME("text/plain"), _as_named_tuple(S)) +# end matching(X) = ModelChecker{false,false,scitype(X),missing}() matching(X, y) = ModelChecker{true,false,scitype(X),scitype(y)}() matching(X, y, w) = ModelChecker{true,true,scitype(X),scitype(y)}() -(f::ModelChecker{false,false,XS})(model::MLJModels.ModelProxy) where XS = +(f::ModelChecker{false,false,XS,missing})(model::MLJModels.ModelProxy) where XS = !(model.is_supervised) && XS <: model.input_scitype @@ -51,6 +84,7 @@ matching(X, y, w) = ModelChecker{true,true,scitype(X),scitype(y)}() yS <: model.target_scitype (f::ModelChecker)(name::String; pkg=nothing) = f(info(name, pkg=pkg)) +(f::ModelChecker)(realmodel::Model) = f(info(realmodel)) matching(model::MLJModels.ModelProxy, args...) = matching(args...)(model) matching(name::String, args...; pkg=nothing) = diff --git a/test/model_matching.jl b/test/model_matching.jl index 349e16294..a73595874 100644 --- a/test/model_matching.jl +++ b/test/model_matching.jl @@ -1,4 +1,4 @@ -module TestMatching +module TestModelMatching using MLJ using Test @@ -23,8 +23,8 @@ m1 = models(matching(X)) @test !(info("PCA") in m1) m2 = models(matching(X, y)) -matching(X, y)("ConstantRegressor") -matching(X,y) +@test info("ConstantRegressor") in m2 +@test !(info("DecisionTreeRegressor") in m2) end true From a923218c98bc071d90212aeef189c0535eb4ccca Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Mon, 16 Sep 2019 08:06:21 +1200 Subject: [PATCH 05/11] Add docstring, manual and cheatsheet updates for matching --- docs/make.jl | 7 ++- docs/src/composing_models.md | 52 ++++++++++------- docs/src/index.md | 2 +- docs/src/mlj_cheatsheet.md | 32 +++++++--- docs/src/model_search.md | 104 +++++++++++++++++++++++++++++++++ docs/src/working_with_tasks.jl | 6 -- src/model_matching.jl | 35 +++++++++++ 7 files changed, 199 insertions(+), 39 deletions(-) create mode 100644 docs/src/model_search.md diff --git a/docs/make.jl b/docs/make.jl index 6836413cf..35e3e8e18 100755 --- a/docs/make.jl +++ b/docs/make.jl @@ -12,16 +12,17 @@ using MLJModels using ScientificTypes pages = Any["Getting Started"=>"index.md", - "Evaluating model performance"=>"evaluating_model_performance.md", + "Model Search" => "model_search.md", + "Evaluating Model Performance"=>"evaluating_model_performance.md", "Performance Measures"=> "performance_measures.md", - "Tuning models"=>"tuning_models.md", + "Tuning Models"=>"tuning_models.md", "Built-in Transformers" => "built_in_transformers.md", "Composing Models" => "composing_models.md", "Homogeneous Ensembles" => "homogeneous_ensembles.md", "Simple User Defined Models" => "simple_user_defined_models.md", "Adding Models for General Use" => "adding_models_for_general_use.md", "Benchmarking" => "benchmarking.md", - "Working with tasks" => "working_with_tasks.md", + "Working with Tasks" => "working_with_tasks.md", "Internals"=>"internals.md", "Glossary"=>"glossary.md", "API"=>"api.md", diff --git a/docs/src/composing_models.md b/docs/src/composing_models.md index fa7520b60..e674bb50f 100644 --- a/docs/src/composing_models.md +++ b/docs/src/composing_models.md @@ -47,20 +47,37 @@ The code also creates an instance of the new pipeline model type, called `pipe`, whose hyperparameters `hot`, `knn`, and `stand` are the component model instances specified in the macro expression: -```@example 7 -pipe = @pipeline MyPipe(X -> coerce(X, :age=>Continuous), - hot = OneHotEncoder(), - knn = KNNRegressor(K=3), - target = UnivariateStandardizer()) -params(pipe) +```julia +julia> pipe = @pipeline MyPipe(X -> coerce(X, :age=>Continuous), + hot = OneHotEncoder(), + knn = KNNRegressor(K=3), + target = UnivariateStandardizer()) + +MyPipe(hot = OneHotEncoder(features = Symbol[], + drop_last = false, + ordered_factor = true,), + knn = KNNRegressor(K = 3, + metric = MLJModels.KNN.euclidean, + kernel = MLJModels.KNN.reciprocal,), + target = UnivariateStandardizer(),) @ 1…39 ``` We can, for example, evaluate the pipeline like we would any other model: -```@example 7 -pipe.knn.K = 2 -pipe.hot.drop_last = true -evaluate(pipe, X, height, resampling=Holdout(), measure=rms, verbosity=0) +```julia +julia> pipe.knn.K = 2 +julia> pipe.hot.drop_last = true +julia> evaluate(pipe, X, height, resampling=Holdout(), measure=rms, verbosity=0) + +[ Info: Training Machine{MyPipe} @ 4…44. +[ Info: Training NodalMachine{OneHotEncoder} @ 1…16. +[ Info: Spawning 1 sub-features to one-hot encode feature :gender. +[ Info: Training NodalMachine{UnivariateStandardizer} @ 5…65. +[ Info: Training NodalMachine{KNNRegressor} @ 1…49. +(measure = MLJBase.RMS[rms], + measurement = [10.0336], + per_fold = Array{Float64,1}[[10.0336]], + per_observation = Missing[missing],) ``` For important details on including target transformations, see below. @@ -120,20 +137,15 @@ The diagram above depicts a learning network which standardizes the input data `X`, learns an optimal Box-Cox transformation for the target `y`, predicts new target values using ridge regression, and then inverse-transforms those predictions, for later comparison with -the original test data. The machines are labeled in yellow. We first -need to import the RidgeRegressor model (you will need `MLJModels` in -your load path): - -```julia -@load RidgeRegressor pkg=MultivariateStats -``` +the original test data. The machines are labeled in yellow. -To implement the network, we begin by loading data needed for training -and evaluation into *source nodes*. For testing purposes, we'll use a -small synthetic data set: +For testing purposes, we'll use a small synthetic data set: ```julia using Statistics, DataFrames + +@load RidgeRegressor pkg=MultivariateStats + x1 = rand(300) x2 = rand(300) x3 = rand(300) diff --git a/docs/src/index.md b/docs/src/index.md index 1134485d9..73969dbcc 100755 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -27,7 +27,7 @@ and then split the data into input and target parts: ```@repl doda using MLJ y, X = unpack(iris, ==(:Species), colname -> true); -first(X, 3) +first(X, 3) |> pretty ``` In MLJ a *model* is a struct storing the hyperparameters of the diff --git a/docs/src/mlj_cheatsheet.md b/docs/src/mlj_cheatsheet.md index 881ae5a8b..318b38ad1 100644 --- a/docs/src/mlj_cheatsheet.md +++ b/docs/src/mlj_cheatsheet.md @@ -7,22 +7,34 @@ #### Model search and code loading -`models()` to list all registered models. +`info("PCA")` retrieves registry metadata for the model called "PCA" + +`info("RidgeRegressor", pkg="MultivariateStats")` retrieves metadata +for "RidgeRegresssor", which is provided by multiple packages + +`models()` lists metadata of every registered model. -`models(x -> x.is_supervised && x.is_pure_julia)` to find all supervised models written in pure julia. +`models(x -> x.is_supervised && x.is_pure_julia)` lists all supervised models written in pure julia. +`models(matching(X))` lists all unsupervised models compatible with input `X`. -`info("PCA")` retrieves registry metadata on the model called "PCA" +`models(matching(X, y))` lists all supervised modesl compatible with input/target `X/y`. -`info("RidgeRegressor", pkg="MultivariateStats")` retrieves metadata -for "RidgeRegresssor", which is provided by multiple packages +With additional conditions: +```julia +models(matching(X, y)) do model + model.prediction_type == :probabilistic && + model.is_pure_julia +end +``` `tree = @load DecisionTreeClassifier` to load code and instantiate "DecisionTreeClassifier" model `tree2 = DecisionTreeClassifier(max_depth=2)` instantiates a model type already in scope -`ridge = @load RidgeRegressor pkg=MultivariateStats` load and instantiate a "RidgeRegressor" model +`ridge = @load RidgeRegressor pkg=MultivariateStats` loads and +instantiates a model provided by multiple packages #### Scitypes and coercion @@ -48,10 +60,11 @@ Use `schema(X)` to get the column scitypes of a table `X` ### Ingesting data -Splitting any table into target and input: +Splitting any table into target and input (note semicolon): ```julia -using RDatasets; channing = dataset("boot", "channing") +using RDatasets +channing = dataset("boot", "channing") y, X = unpack(channing, ==(:Exit), # y is the :Exit column !=(:Time); # X is the rest, except :Time @@ -125,6 +138,7 @@ or a list of pairs of row indices: `evaluate(model, X, y, resampling=CV(), measure=rms, operation=predict, weights=..., verbosity=1)` `evaluate!(mach, resampling=Holdout(), measure=[rms, mav], operation=predict, weights=..., verbosity=1)` +`evaluate!(mach, resampling=[(fold1, fold2), (fold2, fold1)], measure=rms)` #### Ranges for tuning @@ -213,7 +227,7 @@ Supervised, with final node `yhat` returning point-predictions: Supervised, with `yhat` final node returning probabilistic predictions: -`@from_network Composite(knn=network_knn) <= yhat is_probabistic=true` +`@from_network Composite(knn=network_knn) <= yhat is_probabilistic=true` Unsupervised, with final node `Xout`: diff --git a/docs/src/model_search.md b/docs/src/model_search.md new file mode 100644 index 000000000..19e76b4ee --- /dev/null +++ b/docs/src/model_search.md @@ -0,0 +1,104 @@ +# Model Search + +MLJ has a model registry, allowing the user to search models and their +properties, without loading all the packages containing model code. In +turn, this allows one to efficiently find all models solving a given +machine learning task. The task itself is specified with the help of +the `matching` method, and the search executed with the `models` +methods, as detailed below. + +### Model metadata + +In this section the word "model" actually refers to its metadata entry +in the registry, as distinct from instances of model `struct`s +discussed elsewhere in the manual. One can obtain such an entry with +the `info` command: + +```@setup tokai +using MLJ +MLJ.color_off() +``` + +```@repl tokai +info("PCA") +``` + +If two models with the same name occur in different packages, the +package name must be specified, as in `info("LinearRegressor", +pkg="GLM")`. + + +### General model queries + +We list all models with `models()`, and list the models for which code is already +loaded with `localmodels()`: + +```@repl tokai +localmodels() +localmodels()[2] +``` + +If `models` is passed any `Bool`-valued function `test`, it returns every `model` for which `test(model)` is true, as in + +```@repl tokai +test(model) = model.is_supervised && + MLJ.Table(Continuous) <: model.input_scitype && + AbstractVector{<:Multiclass{3}} <: model.target_scitype && + model.prediction_type == :deterministic +models(test) +``` + +Multiple test arguments may be passed to `models`, which are applied conjunctively. + + +### Matching models to data + +Common searches are streamlined with the help of the `matching` +command, defined as follows: + +- `matching(model, X, y) == true` exactly when `model` is supervised + and admits inputs and targets with the scientific types of `X` and + `y`, respectively + +- `matching(model, X) == true` exactly when `model` is unsupervised + and admits inputs with the scientific types of `X`. + +So, to search for all supervised probablistic models handling input +`X` and target `y`, one can define the testing function `task` by + +```julia +task(model) = matching(model, X, y)) && model.is_probabilistic +``` + +And execute the search with + +```julia +models(task) +``` + +Also defined are `Bool`-valued callable objects `matching(model)`, +`matching(X, y)` and `matching(X)`, with obvious behaviour. For example, +`matching(X, y)(model) = matching(model, X, y)`. + +So, to search for all models compatible with input `X` and target `y`, +for example, one executes + +```julia +models(matching(X, y)) +``` + +while the preceding search can be compactly written + +```julia +models(matching(X, y)) do model + model.prediction_type == :probabilistic +end +``` + +### API + +```@docs +models +localmodels +matching +``` diff --git a/docs/src/working_with_tasks.jl b/docs/src/working_with_tasks.jl index 2ccf22fc7..cdd9b27f0 100644 --- a/docs/src/working_with_tasks.jl +++ b/docs/src/working_with_tasks.jl @@ -125,10 +125,4 @@ supervised unsupervised ``` -```@docs -models -``` -```@docs -localmodels -``` diff --git a/src/model_matching.jl b/src/model_matching.jl index 5305b9fee..58845fa6c 100644 --- a/src/model_matching.jl +++ b/src/model_matching.jl @@ -64,6 +64,41 @@ end # show(io, MIME("text/plain"), _as_named_tuple(S)) # end +""" + matching(model, X, y) + +Returns `true` exactly when the registry metadata entry `model` is +supervised and admits inputs and targets with the scientific types of +`X` and `y`, respectively. + + matching(model, X) + +Returns `true` exactly when `model` is unsupervised and admits inputs +with the scientific types of `X`. + + matching(model), matching(X, y), matching(X) + +Curried versions of the preceding methods, i.e., `Bool`-valued +callable objects satisfying `matching(X, y)(model) = matching(model, +X, y)`, etc. + +### Example + + models(matching(X)) + +Finds all unsupervised models compatible with input data `X`. + + models() do model + matching(model, X, y) && model.prediction_type == :probabilistic + end + +Finds all supervised models compatible with input data `X` and target +data `y` and making probabilistic predictions. + + +See also [`models`](@ref) + +""" matching(X) = ModelChecker{false,false,scitype(X),missing}() matching(X, y) = ModelChecker{true,false,scitype(X),scitype(y)}() matching(X, y, w) = ModelChecker{true,true,scitype(X),scitype(y)}() From fd5ed46b3d92c8d452cdc63c1a0b91bcf4d55f8c Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Tue, 17 Sep 2019 10:47:56 +1200 Subject: [PATCH 06/11] minor manual correction --- docs/src/composing_models.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/composing_models.md b/docs/src/composing_models.md index e674bb50f..f32384891 100644 --- a/docs/src/composing_models.md +++ b/docs/src/composing_models.md @@ -67,7 +67,7 @@ We can, for example, evaluate the pipeline like we would any other model: ```julia julia> pipe.knn.K = 2 julia> pipe.hot.drop_last = true -julia> evaluate(pipe, X, height, resampling=Holdout(), measure=rms, verbosity=0) +julia> evaluate(pipe, X, height, resampling=Holdout(), measure=rms, verbosity=2) [ Info: Training Machine{MyPipe} @ 4…44. [ Info: Training NodalMachine{OneHotEncoder} @ 1…16. From 54dd49cbcc5a434804dd2fcb614013dfc445729b Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Tue, 17 Sep 2019 16:04:19 +1200 Subject: [PATCH 07/11] travis change: use julia 1.2 for doc generation --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3b311a04f..29282c438 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ after_success: jobs: include: - stage: "Documentation" - julia: 1.1 + julia: 1.2 os: linux # disable global before_script in order not to install Compose twice before_script: From dace359deb4ec3835f75d173514a081c4c8aa1f4 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Thu, 19 Sep 2019 17:38:02 +1200 Subject: [PATCH 08/11] Lots of manual updates, including new Workflows section --- docs/Project.toml | 6 + docs/make.jl | 8 +- docs/src/common_mlj_workflows.md | 438 +++++++++++++++++++ docs/src/evaluating_model_performance.md | 9 +- docs/src/index.md | 81 ++-- docs/src/internals.md | 9 +- docs/src/machines.md | 95 ++++ docs/src/model_search.md | 8 +- docs/src/workflows_learning_curves.png | Bin 0 -> 63374 bytes docs/src/workflows_learning_curves_large.png | Bin 0 -> 62165 bytes docs/src/workflows_tuning_plot.png | Bin 0 -> 31182 bytes docs/src/workflows_tuning_plot_large.png | Bin 0 -> 31182 bytes docs/src/working_with_tasks.jl | 10 +- src/MLJ.jl | 2 +- src/networks.jl | 13 +- 15 files changed, 627 insertions(+), 52 deletions(-) create mode 100644 docs/src/common_mlj_workflows.md create mode 100644 docs/src/machines.md create mode 100644 docs/src/workflows_learning_curves.png create mode 100644 docs/src/workflows_learning_curves_large.png create mode 100644 docs/src/workflows_tuning_plot.png create mode 100644 docs/src/workflows_tuning_plot_large.png diff --git a/docs/Project.toml b/docs/Project.toml index 4ca116109..35b242382 100755 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -4,7 +4,9 @@ CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DecisionTree = "7806a523-6efd-50cb-b5f6-3fa6f1930dbb" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" LossFunctions = "30fc2ffe-d236-52d8-8643-a9d8f7c094a7" MLJ = "add582a8-e3ab-11e8-2d5e-e98b27df1bc7" MLJBase = "a7f614a8-145f-11e9-1d2a-a57a1082229d" @@ -12,6 +14,8 @@ MLJModels = "d491faf4-2d78-11e9-2867-c94bc002c0b7" Missings = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411" NearestNeighbors = "b8a86587-4115-5ab1-83bc-aa920d37bbce" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" ScientificTypes = "321657f4-b219-11e9-178b-2701a2544e81" @@ -19,3 +23,5 @@ TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" [compat] Documenter = "~0.22" +Missings = "<0.4.2" +julia = "1.2" diff --git a/docs/make.jl b/docs/make.jl index 8bb14562c..97ba4618d 100755 --- a/docs/make.jl +++ b/docs/make.jl @@ -2,7 +2,7 @@ if Base.HOME_PROJECT[] !== nothing Base.HOME_PROJECT[] = abspath(Base.HOME_PROJECT[]) end using Pkg -using Documenter +# using Documenter using MLJ using MLJBase using MLJModels.Transformers @@ -10,8 +10,14 @@ using MLJModels.Constant using MLJModels using ScientificTypes +# using Literate +# Literate.markdown("common_mlj_workflows.jl", ".", +# codefence = "```@example workflows" => "```") + pages = Any["Getting Started"=>"index.md", + "Common MLJ Workflows" => "common_mlj_workflows.md", "Model Search" => "model_search.md", + "Machines" => "machines.md", "Evaluating Model Performance"=>"evaluating_model_performance.md", "Performance Measures"=> "performance_measures.md", "Tuning Models"=>"tuning_models.md", diff --git a/docs/src/common_mlj_workflows.md b/docs/src/common_mlj_workflows.md new file mode 100644 index 000000000..3defc3e6a --- /dev/null +++ b/docs/src/common_mlj_workflows.md @@ -0,0 +1,438 @@ +# Common MLJ Workflows + +## Data ingestion + +```@example workflows +using MLJ; color_off() #hide +using RDatasets +channing = dataset("boot", "channing") +first(channing, 4) +``` + +Inspecting metadata, including column scientific types: + +```@example workflows +schema(channing) +``` + +Unpacking data and correcting for wrong scitypes: + +```@example workflows +y, X = unpack(channing, + ==(:Exit), # y is the :Exit column + !=(:Time); # X is the rest, except :Time + :Exit=>Continuous, + :Entry=>Continuous, + :Cens=>Multiclass) +first(X, 4) +``` + +```@example workflows +y[1:4] +``` + +Loading a built-in supervised dataset: + +```@example workflows +X, y = @load_iris; +first(X, 4) +``` + +```@example workflows +y[1:4] +``` + +## Model search + +*Reference:* [Model Search](model_search.md) + +Searching for a supervised model: + +```@example workflows +X, y = @load_boston +models(matching(X, y)) +``` + +```@example workflows +models(matching(X, y))[6] +``` + +More refined searches: + +```@example workflows +models() do model + matching(model, X, y) && + model.prediction_type == :deterministic && + model.is_pure_julia +end +``` + +Searching for an unsupervised model: + +```@example workflows +models(matching(X)) +``` + +Getting the metadata entry for a given model type: + +```@example workflows +info("PCA") +info("RidgeRegressor", pkg="MultivariateStats") # a model type in multiple packages +``` + +## Instantiating a model + +*Reference:* [Getting Started](index.md) + +```@example workflows +@load DecisionTreeClassifier +model = DecisionTreeClassifier(min_samples_split=5, max_depth=4) +``` + +or + +```@julia +model = @load DecisionTreeClassifier +model.min_samples_split = 5 +model.max_depth = 4 +``` + +## Evaluating a model + +*Reference:* [Evaluating Model Performance](evaluating_model_performance.md) + + +```@example workflows +X, y = @load_boston +model = @load KNNRegressor +evaluate(model, X, y, resampling=CV(nfolds=5), measure=[rms, mav]) +``` + +## Basic fit/evaluate/predict by hand: + +*Reference:* [Getting Started](index.md), [Machines](machines.md), +[Evaluating Model Performance](evaluating_model_performance.md), [Performance Measures](performance_measures.md) + +```@example workflows +using RDatasets +vaso = dataset("robustbase", "vaso"); # a DataFrame +first(vasso, 3) +``` + +```@example workflows +y, X = unpack(vaso, ==(:Y), c -> true; :Y => Multiclass) + +tree_model = @load DecisionTreeClassifier +tree_model.max_depth=2; nothing # hide +``` + +Bind the model and data together in a *machine* , which will +additionally store the learned parameters (*fitresults*) when fit: + +```@example workflows +tree = machine(tree_model, X, y) +``` + +Split row indices into training and evaluation rows: + +```@example workflows +train, test = partition(eachindex(y), 0.7, shuffle=true, rng=1234); # 70:30 split +``` + +Fit on train and evaluate on test: + +```@example workflows +fit!(tree, rows=train) +yhat = predict(tree, rows=test); +mean(cross_entropy(yhat, y[test])) +``` + +Predict on new data: + +```@example workflows +Xnew = (Volume=3*rand(3), Rate=3*rand(3)) +predict(tree, Xnew) # a vector of distributions +``` + +```@example workflows +predict_mode(tree, Xnew) # a vector of point-predictions +``` + +## More performance evaluation examples + +```@example workflows +import LossFunctions.ZeroOneLoss +``` + +Evaluating model + data directly: + +```@example workflows +evaluate(tree_model, X, y, + resampling=Holdout(fraction_train=0.7, shuffle=true, rng=1234), + measure=[cross_entropy, ZeroOneLoss()]) +``` + +If a machine is already defined, as above: + +```@example workflows +evaluate!(tree, + resampling=Holdout(fraction_train=0.7, shuffle=true, rng=1234), + measure=[cross_entropy, ZeroOneLoss()]) +``` + +Using cross-validation: + +```@example workflows +evaluate!(tree, resampling=CV(nfolds=5, shuffle=true, rng=1234), + measure=[cross_entropy, ZeroOneLoss()]) +``` + +With user-specified train/evaluation pairs of row indices: + +```@example workflows +f1, f2, f3 = 1:13, 14:26, 27:36 +pairs = [(f1, vcat(f2, f3)), (f2, vcat(f3, f1)), (f3, vcat(f1, f2))]; +evaluate!(tree, + resampling=pairs, + measure=[cross_entropy, ZeroOneLoss()]) +``` + +Changing a hyperparameter and re-evaluating: + +```@example workflows +tree_model.max_depth = 3 +evaluate!(tree, + resampling=CV(nfolds=5, shuffle=true, rng=1234), + measure=[cross_entropy, ZeroOneLoss()]) +``` + +## Inspecting training results + +Fit a ordinary least square model to some synthetic data: + +```@example workflows +x1 = rand(100) +x2 = rand(100) + +X = (x1=x1, x2=x2) +y = x1 - 2x2 + 0.1*rand(100); + +ols_model = @load LinearRegressor pkg=GLM +ols = machine(ols_model, X, y) +fit!(ols) +``` + +Get a named tuple representing the learned parameters, +human-readable if appropriate: + +```@example workflows +fitted_params(ols) +``` + +Get other training-related information: + +```@example workflows +report(ols) +``` + +## Basic fit/transform for unsupervised models + +Load data: + +```@example workflows +X, y = @load_iris +train, test = partition(eachindex(y), 0.97, shuffle=true, rng=123) +``` + +Instantiate and fit the model/machine: + +```@example workflows +@load PCA +pca_model = PCA(maxoutdim=2) +pca = machine(pca_model, X) +fit!(pca, rows=train) +``` + +Transform selected data bound to the machine: + +```@example workflows +transform(pca, rows=test); +``` + +Transform new data: + +```@example workflows +Xnew = (sepal_length=rand(3), sepal_width=rand(3), + petal_length=rand(3), petal_width=rand(3)); +transform(pca, Xnew) +``` + +## Inverting learned transformations + +```@example workflows +y = rand(100); +stand_model = UnivariateStandardizer() +stand = machine(stand_model, y) +fit!(stand) +z = transform(stand, y); +@assert inverse_transform(stand, z) ≈ y # true +``` + +## Nested hyperparameter tuning + +*Reference:* [Tuning Models](tuning_models.md) + +```@example workflows +X, y = @load_iris; nothing # hide +``` + +Define a model with nested hyperparameters: + +```@example workflows +tree_model = @load DecisionTreeClassifier +forest_model = EnsembleModel(atom=tree_model, n=300) +``` + +Inspect all hyperparameters, even nested ones (returns nested named tuple): + +```@example workflows +params(forest_model) +``` + +Define ranges for hyperparameters to be tuned: + +```@example workflows +r1 = range(forest_model, :bagging_fraction, lower=0.5, upper=1.0, scale=:log10) +``` + +```@example workflows +r2 = range(forest_model, :(atom.n_subfeatures), lower=1, upper=4) # nested +``` + +Wrap the model in a tuning strategy: + +```@example workflows +tuned_forest = TunedModel(model=forest_model, + tuning=Grid(resolution=12), + resampling=CV(nfolds=6), + ranges=[r1, r2], + measure=cross_entropy) +``` + +Bound the wrapped model to data: + +```@example workflows +tuned = machine(tuned_forest, X, y) +``` + +Fitting the resultant machine optimizes the hyperaparameters specified +in `range`, using the specified `tuning` and `resampling` strategies +and performance `measure` (possibly a vector of measures), and +retrains on all data bound to the machine: + +```@example workflows +fit!(tuned) +``` + +Inspecting the optimal model: + +```@example workflows +F = fitted_params(tuned) +``` + +```@example workflows +F.best_model +``` + +Inspecting details of tuning procedure: + +```@example workflows +report(tuned) +``` + +Visualizing these results: + +```julia +using Plots +plot(tuned) +``` + +![](workflows_tuning_plot.png) + +Predicting on new data using the optimized model: + +```@example workflows +predict(tuned, Xnew) +``` + +# Constructing a linear pipeline + +*Reference:* [Composing Models](composing_models.md) + +Constructing a linear (unbranching) pipeline with a learned target +transformation/inverse transformation: + +```@example workflows +X, y = @load_reduced_ames +@load KNNRegressor +pipe = @pipeline MyPipe(X -> coerce(X, :age=>Continuous), + hot = OneHotEncoder(), + knn = KNNRegressor(K=3), + target = UnivariateStandardizer()) +``` + +Evaluating the pipeline (just as you would any other model): + +```@example workflows +pipe.knn.K = 2 +pipe.hot.drop_last = true +evaluate(pipe, X, y, resampling=Holdout(), measure=rms, verbosity=2) +``` + +Constructing a linear (unbranching) pipeline with a static (unlearned) +target transformation/inverse transformation: + +```@example workflows +@load DecisionTreeRegressor +pipe2 = @pipeline MyPipe2(X -> coerce(X, :age=>Continuous), + hot = OneHotEncoder(), + tree = DecisionTreeRegressor(max_depth=4), + target = y -> log.(y), + inverse = z -> exp.(z)) +``` + +# Creating a homogeneous ensemble of models + +*Reference:* [Homogeneous Ensembles](homogeneous_ensembles.md) + +```@example workflows +X, y = @load_iris +tree_model = @load DecisionTreeClassifier +forest_model = EnsembleModel(atom=tree_model, bagging_fraction=0.8, n=300) +forest = machine(forest_model, X, y) +evaluate!(forest, measure=cross_entropy) +``` + +# Performance curves + +Generate a plot of performance, as a function of some hyperparameter +(building on the preceding example): + +```@example workflows +r = range(forest_model, :n, lower=1, upper=1000, scale=:log10) +curve = MLJ.learning_curve!(forest, + range=r, + resampling=Holdout(), + measure=cross_entropy, + n=4, + verbosity=0) +``` + +```julia +using Plots +plot(curve.parameter_values, curve.measurements, xlab=curve.parameter_name, xscale=curve.parameter_scale) +``` + +![](workflows_learning_curves.png) + + diff --git a/docs/src/evaluating_model_performance.md b/docs/src/evaluating_model_performance.md index e63886983..766edcfac 100644 --- a/docs/src/evaluating_model_performance.md +++ b/docs/src/evaluating_model_performance.md @@ -1,8 +1,9 @@ -# Evaluation of supervised models +# Evaluating Model Performance -MLJ allows quick evaluation of a model's performance against a battery -of selected losses or scores. For more on available performance -measures, see [Performance Measures](performance_measures.md). +MLJ allows quick evaluation of a supervised model's performance +against a battery of selected losses or scores. For more on available +performance measures, see [Performance +Measures](performance_measures.md). In addition to hold-out and cross-validation, the user can specify their own list of train/evaluation pairs of row indices for diff --git a/docs/src/index.md b/docs/src/index.md index 73969dbcc..842a01352 100755 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,8 +1,8 @@ -# Getting Started +### [Installation](https://github.com/alan-turing-institute/MLJ.jl/blob/master/README.md) | [Cheatsheet](mlj_cheatsheet.md) | [Workflows](common_mlj_workflows.md) | [Workflows](common_mlj_workflows.md) + -#### [Installation instructions](https://github.com/alan-turing-institute/MLJ.jl/blob/master/README.md) +# Getting Started -#### [Cheatsheet](mlj_cheatsheet.md) ```@setup doda import Base.eval # hack b/s auto docs put's code in baremodule @@ -12,10 +12,9 @@ MLJ.color_off() seed!(1234) ``` +### Choosing and evaluating a model -### Plug-and-play model evaluation - -To load some data add +To load some demonstration data, add [RDatasets](https://github.com/JuliaStats/RDatasets.jl) to your load path and enter ```@repl doda @@ -30,10 +29,17 @@ y, X = unpack(iris, ==(:Species), colname -> true); first(X, 3) |> pretty ``` +To seach MJL's [model registry](model_search.md) for models that can +be immediately trained on the data, we run + +```@repl doda +models(matching(X, y)) +``` + In MLJ a *model* is a struct storing the hyperparameters of the learning algorithm indicated by the struct name. -Assuming the DecisionTree package is in your load path, we can use +Assuming the DecisionTree.jl package is in your load path, we can use `@load` to load the code defining the `DecisionTreeClassifier` model type. This macro also returns an instance, with default hyperparameters. @@ -44,7 +50,7 @@ Drop the `verbosity=1` declaration for silent loading: tree_model = @load DecisionTreeClassifier verbosity=1 ``` -*Important:* DecisionTree and most other packages implementing machine +*Important:* DecisionTree.jl and most other packages implementing machine learning algorithms for use in MLJ are not MLJ dependencies. If such a package is not in your load path you will receive an error explaining how to add the package to your current environment. @@ -57,7 +63,7 @@ evaluate(tree_model, X, y, ``` Evaluating against multiple performance measures is also possible. See -[Evaluating model performance](evaluating_model_performance.md) for details. +[Evaluating Model Performance](evaluating_model_performance.md) for details. ### Fit and predict @@ -92,20 +98,35 @@ broadcast(pdf, yhat[3:5], "virginica") # predicted probabilities of virginica mode.(yhat[3:5]) ``` -One can explicitly get modes by using `predict_mode` instead of `predict`: +Or, one can explicitly get modes by using `predict_mode` instead of +`predict`: ```@repl doda predict_mode(tree, rows=test[3:5]) ``` -Machines have an internal state which allows them to avoid redundant -calculations when retrained, in certain conditions - for example when -increasing the number of trees in a random forest, or the number of -epochs in a neural network. The machine building syntax also -anticipates a more general syntax for composing multiple models, as -explained in [Composing Models](composing_models.md). +Unsupervised models have a `transform` method instead of `predict`, +and may optionally implement an `inverse_transform` method: -There is a version of `evaluate` for machines as well as models: +```@repl doda +v = [1, 2, 3, 4] +stand_model = UnivariateStandardizer() +stand = machine(stand_model, v) +fit!(stand) +w = transform(stand, v) +inverse_transform(stand, w) +``` + +[Machines](machines.md) have an internal state which allows them to +avoid redundant calculations when retrained, in certain conditions - +for example when increasing the number of trees in a random forest, or +the number of epochs in a neural network. The machine building syntax +also anticipates a more general syntax for composing multiple models, +as explained in [Composing Models](composing_models.md). + +There is a version of `evaluate` for machines as well as models. An +exclamation point is added to the method name because machines are +generally mutated when trained: ```@repl doda evaluate!(tree, resampling=Holdout(fraction_train=0.5, shuffle=true), @@ -124,9 +145,10 @@ evaluate!(tree, resampling=Holdout(fraction_train=0.5, shuffle=true), ### Next steps To learn a little more about what MLJ can do, take the MLJ -[tour](https://github.com/alan-turing-institute/MLJ.jl/blob/master/examples/tour/tour.ipynb), -and then return to the manual as needed. *Read at least the remainder -of this page before considering serious use of MLJ.* +[tour](https://github.com/alan-turing-institute/MLJ.jl/blob/master/examples/tour/tour.ipynb) +or browse [Common MLJ Workflows](common_mlj_workflows), returning to +the manual as needed. *Read at least the remainder of this page before +considering serious use of MLJ.* ### Prerequisites @@ -155,9 +177,11 @@ Each supervised model in MLJ declares the permitted *scientific type* of the inputs `X` and targets `y` that can be bound to it in the first constructor above, rather than specifying specific machine types (such as `Array{Float32, 2}`). Similar remarks apply to the input `X` of an -unsupervised model. Scientific types are julia types defined in the +unsupervised model. + +Scientific types are julia types defined in the package -[ScientificTypes.jl](https://github.com/alan-turing-institute/ScientificTypes.jl), +rows=nothing, verbosity::Int=1, force::Bool=false), which also defines the convention used here (and there called *mlj*) for assigning a specific scientific type (interpretation) to each julia object (see the `scitype` examples below). @@ -165,7 +189,12 @@ julia object (see the `scitype` examples below). The basic "scalar" scientific types are `Continuous`, `Multiclass{N}`, `OrderedFactor{N}` and `Count`. Be sure you read [Container element types](@ref) below to be guarantee your scalar data is interpreted -correctly. Additionally, most data containers - such as tuples, +correctly. Tools exist to coerce the data to have the appropriate +scientfic type; see +[ScientificTypes.jl](https://github.com/alan-turing-institute/ScientificTypes.jl) +or run `?coerce` for details. + +Additionally, most data containers - such as tuples, vectors, matrices and tables - have a scientific type. @@ -246,9 +275,6 @@ entry, using `info`: info("DecisionTreeClassifier") ``` -See also [Working with tasks](working_with_tasks.md) on searching for -models solving a specified task. - #### Container element types @@ -273,9 +299,6 @@ are the key aspects of that convention: - In particular, *integers* (including `Bool`s) *cannot be used to represent categorical data.* -To coerce the scientific type of a vector or table, use the `coerce` -method (re-exported from -[ScientificTypes.jl](https://github.com/alan-turing-institute/ScientificTypes.jl)). diff --git a/docs/src/internals.md b/docs/src/internals.md index 46342ec7c..90ddae3f7 100755 --- a/docs/src/internals.md +++ b/docs/src/internals.md @@ -1,4 +1,4 @@ -# Internals +G# Internals ### The machine interface, simplified @@ -15,7 +15,7 @@ mutable struct Machine{M1BZe92>3*7j}i;`2iD=8 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

0$qS)lHC=ts_?}Y>fd( z;nhP%k$dBZ<$$0$3Q$5|&DOtLz;)HFpSS4Fk)gRjXvHKrUwGl~2QB^Ea+^0but;0% zey#K82liW|kBFub%M}TZFdw1aqVFNPW_X9Gz5S(J=B6HLICKgpp0+;AOd9JE(`0$P zlSgt0@O%{D4*Z`pk~x0@e~!qRso=HtS5jn2W$iBV^fC05Iq)P}eULgPkf4XB#12o8 z6Dh)ARsC~*@@aeffvvi++477Pi_lIII~T6(ym&DlGIV%h--=U;ZL8Ll;m2mhNmV-B za+`IXR$N$9?uFYh1UXcO36u8rX7OSRJU^f3AR5dI3MsJudtv@WSAzYXNDegDHh~SrP)Mn zB5S2WkZta^W&W9vK8qaeSBnf_W1dMb^F-moB4>Zv6XxraP!+qUEs+-Y?1KM#zD z-@^_pIN%J#$KSW$R!^ixJ^fc5hbHQQcZ|+b=fnHDhQ^k9z`Z=E;|r(JqaJ&t_uOiK zN+j(G{dsyIbESC z+>L)eg5jhp>*<;D?N(u3bfO*EBEw$cevqqkI7KF9Eg*sP8l z(pYefopeGbs;_djdu1DFy1({K+{63EFIAjNTYFEQYLpUWqQjHU|FV$A(p55 zZJ(wE&TFQEXA{vL_i-S5H_ePJv3T;)+Wdo}8Kg#~yJDOBbw*J&u@&?HV*?cF?)ogWIBv;zRsNTKV^M1G(>K$c*-^ zae>-9U{g$L&i<^?^Mb^*vaRB0cEPjeFsg_DJdP7kMDV(E73#&|aYX58g8&*zt!~HB?K7RKNm*b)Ng>)81;^DC|7X&SCr!uxM zT~VMv;5YVmB6%aTNBa`n&-0C`XMvMB$a!7e{qsV`Nx%P!xv+Xsj8Rt#d;X{RyM8Is z___5Be^x6u4E-X+a!vp7$PmS6wazzH3J{vx--w%ppD4X7{Yd(uxrwevbC#AOVtZc@ zPA*9MeV#&TdEPTq&N|j|V?SMr+U _U@~Ue7y<1t8WpSuip>dgz5R)5sNP5%B=Z? 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 W?m5SIrAo#R28x-H6}lAV689g#V}jHG literal 0 HcmV?d00001 diff --git a/docs/src/workflows_tuning_plot.png b/docs/src/workflows_tuning_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..aadf74652d2c6583628310d6d586c7eaf317c612 GIT binary patch literal 31182 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≈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≈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 mYI3lm<}!cMS5onc`1f^XM Date: Fri, 20 Sep 2019 08:55:19 +1200 Subject: [PATCH 09/11] temporarily add workflows notebook --- docs/src/common_mlj_workflows.ipynb | 1855 +++++++++++++++++++++++++++ 1 file changed, 1855 insertions(+) create mode 100644 docs/src/common_mlj_workflows.ipynb diff --git a/docs/src/common_mlj_workflows.ipynb b/docs/src/common_mlj_workflows.ipynb new file mode 100644 index 000000000..58786215d --- /dev/null +++ b/docs/src/common_mlj_workflows.ipynb @@ -0,0 +1,1855 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Common MLJ Workflows" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data ingestion" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "using MLJ\n", + "using RDatasets\n", + "channing = dataset(\"boot\", \"channing\");" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Inspecting metadata, including column scientific types:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(names = (:Sex, :Entry, :Exit, :Time, :Cens),\n", + " types = (CategoricalString{UInt8}, Int32, Int32, Int32, Int32),\n", + " scitypes = (Multiclass{2}, Count, Count, Count, Count),\n", + " nrows = 462,)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "schema(channing)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Unpacking data and correcting for wrong scitypes:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌\u001b[0m──────────────────────────\u001b[0m┬\u001b[0m────────────\u001b[0m┬\u001b[0m───────────────────────────────\u001b[0m┐\u001b[0m\n", + "│\u001b[0m\u001b[1m Sex \u001b[0m│\u001b[0m\u001b[1m Entry \u001b[0m│\u001b[0m\u001b[1m Cens \u001b[0m│\u001b[0m\n", + "│\u001b[0m\u001b[90m CategoricalString{UInt8} \u001b[0m│\u001b[0m\u001b[90m Float64 \u001b[0m│\u001b[0m\u001b[90m CategoricalValue{Int32,UInt8} \u001b[0m│\u001b[0m\n", + "│\u001b[0m\u001b[90m Multiclass{2} \u001b[0m│\u001b[0m\u001b[90m Continuous \u001b[0m│\u001b[0m\u001b[90m Multiclass{2} \u001b[0m│\u001b[0m\n", + "├\u001b[0m──────────────────────────\u001b[0m┼\u001b[0m────────────\u001b[0m┼\u001b[0m───────────────────────────────\u001b[0m┤\u001b[0m\n", + "│\u001b[0m Male \u001b[0m│\u001b[0m 782.0 \u001b[0m│\u001b[0m 1 \u001b[0m│\u001b[0m\n", + "│\u001b[0m Male \u001b[0m│\u001b[0m 1020.0 \u001b[0m│\u001b[0m 1 \u001b[0m│\u001b[0m\n", + "│\u001b[0m Male \u001b[0m│\u001b[0m 856.0 \u001b[0m│\u001b[0m 1 \u001b[0m│\u001b[0m\n", + "│\u001b[0m Male \u001b[0m│\u001b[0m 915.0 \u001b[0m│\u001b[0m 1 \u001b[0m│\u001b[0m\n", + "└\u001b[0m──────────────────────────\u001b[0m┴\u001b[0m────────────\u001b[0m┴\u001b[0m───────────────────────────────\u001b[0m┘\u001b[0m\n" + ] + } + ], + "source": [ + "y, X = unpack(channing,\n", + " ==(:Exit), # y is the :Exit column\n", + " !=(:Time); # X is the rest, except :Time\n", + " :Exit=>Continuous,\n", + " :Entry=>Continuous,\n", + " :Cens=>Multiclass)\n", + "first(X, 4) |> pretty" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Array{Float64,1}:\n", + " 909.0\n", + " 1128.0\n", + " 969.0\n", + " 957.0" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y[1:4]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading a built-in supervised dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌\u001b[0m──────────────\u001b[0m┬\u001b[0m─────────────\u001b[0m┬\u001b[0m──────────────\u001b[0m┬\u001b[0m─────────────\u001b[0m┐\u001b[0m\n", + "│\u001b[0m\u001b[1m sepal_length \u001b[0m│\u001b[0m\u001b[1m sepal_width \u001b[0m│\u001b[0m\u001b[1m petal_length \u001b[0m│\u001b[0m\u001b[1m petal_width \u001b[0m│\u001b[0m\n", + "│\u001b[0m\u001b[90m Float64 \u001b[0m│\u001b[0m\u001b[90m Float64 \u001b[0m│\u001b[0m\u001b[90m Float64 \u001b[0m│\u001b[0m\u001b[90m Float64 \u001b[0m│\u001b[0m\n", + "│\u001b[0m\u001b[90m Continuous \u001b[0m│\u001b[0m\u001b[90m Continuous \u001b[0m│\u001b[0m\u001b[90m Continuous \u001b[0m│\u001b[0m\u001b[90m Continuous \u001b[0m│\u001b[0m\n", + "├\u001b[0m──────────────\u001b[0m┼\u001b[0m─────────────\u001b[0m┼\u001b[0m──────────────\u001b[0m┼\u001b[0m─────────────\u001b[0m┤\u001b[0m\n", + "│\u001b[0m 5.1 \u001b[0m│\u001b[0m 3.5 \u001b[0m│\u001b[0m 1.4 \u001b[0m│\u001b[0m 0.2 \u001b[0m│\u001b[0m\n", + "│\u001b[0m 4.9 \u001b[0m│\u001b[0m 3.0 \u001b[0m│\u001b[0m 1.4 \u001b[0m│\u001b[0m 0.2 \u001b[0m│\u001b[0m\n", + "│\u001b[0m 4.7 \u001b[0m│\u001b[0m 3.2 \u001b[0m│\u001b[0m 1.3 \u001b[0m│\u001b[0m 0.2 \u001b[0m│\u001b[0m\n", + "│\u001b[0m 4.6 \u001b[0m│\u001b[0m 3.1 \u001b[0m│\u001b[0m 1.5 \u001b[0m│\u001b[0m 0.2 \u001b[0m│\u001b[0m\n", + "└\u001b[0m──────────────\u001b[0m┴\u001b[0m─────────────\u001b[0m┴\u001b[0m──────────────\u001b[0m┴\u001b[0m─────────────\u001b[0m┘\u001b[0m\n" + ] + } + ], + "source": [ + "X, y = @load_iris;\n", + "first(X, 4) |> pretty" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element CategoricalArray{String,1,UInt32}:\n", + " \"setosa\"\n", + " \"setosa\"\n", + " \"setosa\"\n", + " \"setosa\"" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y[1:4]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model search" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Searching for a supervised model:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "37-element Array{NamedTuple,1}:\n", + " (name = ARDRegressor, package_name = ScikitLearn, ... ) \n", + " (name = AdaBoostRegressor, package_name = ScikitLearn, ... ) \n", + " (name = BaggingRegressor, package_name = ScikitLearn, ... ) \n", + " (name = BayesianRidgeRegressor, package_name = ScikitLearn, ... ) \n", + " (name = ConstantRegressor, package_name = MLJModels, ... ) \n", + " (name = DecisionTreeRegressor, package_name = DecisionTree, ... ) \n", + " (name = DeterministicConstantRegressor, package_name = MLJModels, ... ) \n", + " (name = ElasticNetCVRegressor, package_name = ScikitLearn, ... ) \n", + " (name = ElasticNetRegressor, package_name = ScikitLearn, ... ) \n", + " (name = EpsilonSVR, package_name = LIBSVM, ... ) \n", + " (name = GaussianProcessRegressor, package_name = ScikitLearn, ... ) \n", + " (name = GradientBoostingRegressor, package_name = ScikitLearn, ... ) \n", + " (name = HuberRegressor, package_name = ScikitLearn, ... ) \n", + " ⋮ \n", + " (name = OrthogonalMatchingPursuitRegressor, package_name = ScikitLearn, ... )\n", + " (name = PassiveAggressiveRegressor, package_name = ScikitLearn, ... ) \n", + " (name = RandomForestRegressor, package_name = ScikitLearn, ... ) \n", + " (name = RidgeCVRegressor, package_name = ScikitLearn, ... ) \n", + " (name = RidgeRegressor, package_name = MultivariateStats, ... ) \n", + " (name = RidgeRegressor, package_name = ScikitLearn, ... ) \n", + " (name = SGDRegressor, package_name = ScikitLearn, ... ) \n", + " (name = SVMLRegressor, package_name = ScikitLearn, ... ) \n", + " (name = SVMNuRegressor, package_name = ScikitLearn, ... ) \n", + " (name = SVMRegressor, package_name = ScikitLearn, ... ) \n", + " (name = TheilSenRegressor, package_name = ScikitLearn, ... ) \n", + " (name = XGBoostRegressor, package_name = XGBoost, ... ) " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X, y = @load_boston\n", + "models(matching(X, y))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[35mDecisionTreeRegressor from DecisionTree.jl.\u001b[39m\n", + "\u001b[35m[Documentation](https://github.com/bensadeghi/DecisionTree.jl).\u001b[39m\n", + "(name = \"DecisionTreeRegressor\",\n", + " package_name = \"DecisionTree\",\n", + " is_supervised = true,\n", + " docstring = \"DecisionTreeRegressor from DecisionTree.jl.\\n[Documentation](https://github.com/bensadeghi/DecisionTree.jl).\",\n", + " hyperparameter_types = [\"Float64\", \"Int64\", \"Int64\", \"Int64\", \"Float64\", \"Int64\", \"Bool\"],\n", + " hyperparameters = Symbol[:pruning_purity_threshold, :max_depth, :min_samples_leaf, :min_samples_split, :min_purity_increase, :n_subfeatures, :post_prune],\n", + " implemented_methods = Symbol[:fit, :predict, :clean!, :fitted_params],\n", + " is_pure_julia = true,\n", + " is_wrapper = false,\n", + " load_path = \"MLJModels.DecisionTree_.DecisionTreeRegressor\",\n", + " package_license = \"unknown\",\n", + " package_url = \"https://github.com/bensadeghi/DecisionTree.jl\",\n", + " package_uuid = \"7806a523-6efd-50cb-b5f6-3fa6f1930dbb\",\n", + " prediction_type = :deterministic,\n", + " supports_weights = false,\n", + " input_scitype = ScientificTypes.Table{_s13} where _s13<:(AbstractArray{_s12,1} where _s12<:Continuous),\n", + " target_scitype = AbstractArray{_s491,1} where _s491<:Continuous,)" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "models(matching(X, y))[6]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "More refined searches:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Array{NamedTuple,1}:\n", + " (name = DecisionTreeRegressor, package_name = DecisionTree, ... ) \n", + " (name = DeterministicConstantRegressor, package_name = MLJModels, ... )\n", + " (name = KNNRegressor, package_name = NearestNeighbors, ... ) \n", + " (name = RidgeRegressor, package_name = MultivariateStats, ... ) " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "models() do model\n", + " matching(model, X, y) &&\n", + " model.prediction_type == :deterministic &&\n", + " model.is_pure_julia\n", + "end" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Searching for an unsupervised model:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9-element Array{NamedTuple,1}:\n", + " (name = FeatureSelector, package_name = MLJModels, ... ) \n", + " (name = ICA, package_name = MultivariateStats, ... ) \n", + " (name = KMeans, package_name = Clustering, ... ) \n", + " (name = KMedoids, package_name = Clustering, ... ) \n", + " (name = KernelPCA, package_name = MultivariateStats, ... )\n", + " (name = OneClassSVM, package_name = LIBSVM, ... ) \n", + " (name = OneHotEncoder, package_name = MLJModels, ... ) \n", + " (name = PCA, package_name = MultivariateStats, ... ) \n", + " (name = Standardizer, package_name = MLJModels, ... ) " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "models(matching(X))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Getting the metadata entry for a given model type:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[35mRidgeRegressor from MultivariateStats.jl.\u001b[39m\n", + "\u001b[35m[Documentation](https://github.com/JuliaStats/MultivariateStats.jl).\u001b[39m\n", + "(name = \"RidgeRegressor\",\n", + " package_name = \"MultivariateStats\",\n", + " is_supervised = true,\n", + " docstring = \"RidgeRegressor from MultivariateStats.jl.\\n[Documentation](https://github.com/JuliaStats/MultivariateStats.jl).\",\n", + " hyperparameter_types = [\"Float64\"],\n", + " hyperparameters = Symbol[:lambda],\n", + " implemented_methods = Symbol[:fit, :predict, :clean!, :fitted_params],\n", + " is_pure_julia = true,\n", + " is_wrapper = false,\n", + " load_path = \"MLJModels.MultivariateStats_.RidgeRegressor\",\n", + " package_license = \"unknown\",\n", + " package_url = \"https://github.com/JuliaStats/MultivariateStats.jl\",\n", + " package_uuid = \"6f286f6a-111f-5878-ab1e-185364afe411\",\n", + " prediction_type = :deterministic,\n", + " supports_weights = false,\n", + " input_scitype = ScientificTypes.Table{_s13} where _s13<:(AbstractArray{_s12,1} where _s12<:Continuous),\n", + " target_scitype = AbstractArray{Continuous,1},)" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "info(\"PCA\")\n", + "info(\"RidgeRegressor\", pkg=\"MultivariateStats\") # a model type in multiple packages" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### *More on model matching*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `model` is in the list returned by `models(test)` exactly when\n", + " `test(model) == true`. (Here `model` is some model type metadata\n", + " entry, as returned by `info(...)`.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `matching(model, X, y) == true` exactly when `model` is supervised\n", + " and admits inputs and targets with the scientific types of `X` and\n", + " `y`, respectively." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `matching(model, X) == true` exaclty when `model` is unsupervised\n", + " and admits inputs with the scientific types of `X`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- The testing objects `matching(model)`, `matching(X, y)` and `matching(X)`,\n", + " which are callable and `Bool`-valued, are just the curried versions of\n", + " the above. So, for example, `matching(X, y)(model) =\n", + " matching(model, X, y)`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiating a model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading model code:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "DecisionTreeClassifier(pruning_purity = 1.0,\n", + " max_depth = -1,\n", + " min_samples_leaf = 1,\n", + " min_samples_split = 2,\n", + " min_purity_increase = 0.0,\n", + " n_subfeatures = 0,\n", + " display_depth = 5,\n", + " post_prune = false,\n", + " merge_purity_threshold = 0.9,\n", + " pdf_smoothing = 0.05,)\u001b[34m @ 7…72\u001b[39m" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@load DecisionTreeClassifier" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instantiating a model:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "DecisionTreeClassifier(pruning_purity = 1.0,\n", + " max_depth = 4,\n", + " min_samples_leaf = 1,\n", + " min_samples_split = 5,\n", + " min_purity_increase = 0.0,\n", + " n_subfeatures = 0,\n", + " display_depth = 5,\n", + " post_prune = false,\n", + " merge_purity_threshold = 0.9,\n", + " pdf_smoothing = 0.05,)\u001b[34m @ 7…86\u001b[39m" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model = DecisionTreeClassifier(min_samples_split=5, max_depth=4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: A model type \"DecisionTreeClassifier\" is already loaded. \n", + "│ No new code loaded. \n", + "└ @ MLJModels /Users/anthony/Dropbox/Julia7/MLJ/MLJModels/src/loading.jl:41\n" + ] + }, + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model = @load DecisionTreeClassifier\n", + "model.min_samples_split = 5\n", + "model.max_depth = 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluating a model:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[33mEvaluating over 5 folds: 100%[=========================] Time: 0:00:02\u001b[39m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌\u001b[0m─────────\u001b[0m┬\u001b[0m───────────────────\u001b[0m┐\u001b[0m\n", + "│\u001b[0m\u001b[1m measure \u001b[0m│\u001b[0m\u001b[1m measurement \u001b[0m│\u001b[0m\n", + "├\u001b[0m─────────\u001b[0m┼\u001b[0m───────────────────\u001b[0m┤\u001b[0m\n", + "│\u001b[0m rms \u001b[0m│\u001b[0m 8.668102471357711 \u001b[0m│\u001b[0m\n", + "│\u001b[0m mav \u001b[0m│\u001b[0m 6.047643564356435 \u001b[0m│\u001b[0m\n", + "└\u001b[0m─────────\u001b[0m┴\u001b[0m───────────────────\u001b[0m┘\u001b[0m\n" + ] + }, + { + "data": { + "text/plain": [ + "(measure = MLJBase.Measure[rms, mav],\n", + " measurement = [8.668102471357711, 6.047643564356435],\n", + " per_fold = Array{Float64,1}[[8.525465870955774, 8.52461967445231, 10.74455588603451, 9.393386761519249, 6.152484163826722], [6.489306930693069, 5.434059405940592, 7.613069306930692, 6.033663366336635, 4.668118811881189]],\n", + " per_observation = Missing[missing, missing],)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X, y = @load_boston\n", + "model = @load KNNRegressor\n", + "evaluate(model, X, y, resampling=CV(nfolds=5), measure=[rms, mav])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic fit/evaluate/predict by hand:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: A model type \"DecisionTreeClassifier\" is already loaded. \n", + "│ No new code loaded. \n", + "└ @ MLJModels /Users/anthony/Dropbox/Julia7/MLJ/MLJModels/src/loading.jl:41\n" + ] + }, + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "using RDatasets\n", + "vaso = dataset(\"robustbase\", \"vaso\"); # a DataFrame\n", + "y, X = unpack(vaso, ==(:Y), c -> true; :Y => Multiclass)\n", + "\n", + "tree_model = @load DecisionTreeClassifier\n", + "tree_model.max_depth=2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bind the model and data together in a *machine* , which will\n", + "additionally store the learned parameters (*fitresults*) when fit:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[34mMachine{DecisionTreeClassifier} @ 1…17\u001b[39m\n" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tree = machine(tree_model, X, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Split row indices into training and evaluation rows:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "train, test = partition(eachindex(y), 0.7, shuffle=true, rng=1234); # 70:30 split" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fit on train and evaluate on test:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: Training \u001b[34mMachine{DecisionTreeClassifier} @ 1…17\u001b[39m.\n", + "└ @ MLJ /Users/anthony/Dropbox/Julia7/MLJ/MLJ/src/machines.jl:141\n" + ] + }, + { + "data": { + "text/plain": [ + "1.135369212298553" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fit!(tree, rows=train)\n", + "yhat = predict(tree, rows=test);\n", + "mean(cross_entropy(yhat, y[test]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Predict on new data:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Array{UnivariateFinite{Int64,UInt8,Float64},1}:\n", + " UnivariateFinite(0=>0.2727272727272727, 1=>0.7272727272727273) \n", + " UnivariateFinite(0=>0.02439024390243903, 1=>0.9756097560975611)\n", + " UnivariateFinite(0=>0.02439024390243903, 1=>0.9756097560975611)" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Xnew = (Volume=3*rand(3), Rate=3*rand(3))\n", + "predict(tree, Xnew) # a vector of distributions" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Array{CategoricalValue{Int64,UInt8},1}:\n", + " 1\n", + " 1\n", + " 1" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "predict_mode(tree, Xnew) # a vector of point-predictions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### *More on machines (implementation detail)*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Under the hood, calling `fit!` on a machine calls either\n", + "`MLJBase.fit` or `MLJBase.update` depending on the machine's\n", + "internal state, as recorded in additional fields `previous_model`\n", + "and `rows`. These lower level methods dispatch on the model and a\n", + "view of the data depending on the optional `rows` keyword argument\n", + "of `fit!` (all rows by default). In this way, if a model `update`\n", + "method is implemented, calls to `fit!` can avoid redundant\n", + "calculations for certain kinds of model mutations (eg, increasing\n", + "the number of epochs in a neural network)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is a complete list of the fields of a machine:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `model` - the struct containing the hyperparameters to be used\n", + "in calls to `fit!`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `fitresult` - the learned parameters in a raw form, initially undefined" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `args` - a tuple of the data (in the supervised learning example above, `args = (X, y)`)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `report` - outputs of training not encoded in `fitresult` (eg, feature rankings)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `previous_model` - a deep copy of the model used in the last call to `fit!`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `rows` - a copy of the row indices used in last call to `fit!`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `cache`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## More performance evaluation examples:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "import LossFunctions.ZeroOneLoss" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Evaluating model + data directly:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌\u001b[0m───────────────\u001b[0m┬\u001b[0m────────────────────\u001b[0m┐\u001b[0m\n", + "│\u001b[0m\u001b[1m measure \u001b[0m│\u001b[0m\u001b[1m measurement \u001b[0m│\u001b[0m\n", + "├\u001b[0m───────────────\u001b[0m┼\u001b[0m────────────────────\u001b[0m┤\u001b[0m\n", + "│\u001b[0m cross_entropy \u001b[0m│\u001b[0m 1.135369212298553 \u001b[0m│\u001b[0m\n", + "│\u001b[0m ZeroOneLoss \u001b[0m│\u001b[0m 0.4166666666666667 \u001b[0m│\u001b[0m\n", + "└\u001b[0m───────────────\u001b[0m┴\u001b[0m────────────────────\u001b[0m┘\u001b[0m\n" + ] + }, + { + "data": { + "text/plain": [ + "(measure = Any[cross_entropy, ZeroOneLoss()],\n", + " measurement = [1.135369212298553, 0.4166666666666667],\n", + " per_fold = Array{Float64,1}[[1.135369212298553], [0.4166666666666667]],\n", + " per_observation = Array{Array{Float64,1},1}[[[0.10536051565782628, 3.7135720667043075, 0.10536051565782628, 2.3025850929940455, 0.10536051565782628, 0.3184537311185346, 0.02469261259037141, 0.3184537311185346, 0.3184537311185346, 1.2992829841302609, 3.7135720667043075, 1.2992829841302609]], [[0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0]]],)" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "evaluate(tree_model, X, y,\n", + " resampling=Holdout(fraction_train=0.7, shuffle=true, rng=1234),\n", + " measure=[cross_entropy, ZeroOneLoss()])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If a machine is already defined, as above:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌\u001b[0m───────────────\u001b[0m┬\u001b[0m────────────────────\u001b[0m┐\u001b[0m\n", + "│\u001b[0m\u001b[1m measure \u001b[0m│\u001b[0m\u001b[1m measurement \u001b[0m│\u001b[0m\n", + "├\u001b[0m───────────────\u001b[0m┼\u001b[0m────────────────────\u001b[0m┤\u001b[0m\n", + "│\u001b[0m cross_entropy \u001b[0m│\u001b[0m 1.135369212298553 \u001b[0m│\u001b[0m\n", + "│\u001b[0m ZeroOneLoss \u001b[0m│\u001b[0m 0.4166666666666667 \u001b[0m│\u001b[0m\n", + "└\u001b[0m───────────────\u001b[0m┴\u001b[0m────────────────────\u001b[0m┘\u001b[0m\n" + ] + }, + { + "data": { + "text/plain": [ + "(measure = Any[cross_entropy, ZeroOneLoss()],\n", + " measurement = [1.135369212298553, 0.4166666666666667],\n", + " per_fold = Array{Float64,1}[[1.135369212298553], [0.4166666666666667]],\n", + " per_observation = Array{Array{Float64,1},1}[[[0.10536051565782628, 3.7135720667043075, 0.10536051565782628, 2.3025850929940455, 0.10536051565782628, 0.3184537311185346, 0.02469261259037141, 0.3184537311185346, 0.3184537311185346, 1.2992829841302609, 3.7135720667043075, 1.2992829841302609]], [[0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0]]],)" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "evaluate!(tree,\n", + " resampling=Holdout(fraction_train=0.7, shuffle=true, rng=1234),\n", + " measure=[cross_entropy, ZeroOneLoss()])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using cross-validation:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[33mEvaluating over 5 folds: 100%[=========================] Time: 0:00:00\u001b[39m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌\u001b[0m───────────────\u001b[0m┬\u001b[0m────────────────────\u001b[0m┐\u001b[0m\n", + "│\u001b[0m\u001b[1m measure \u001b[0m│\u001b[0m\u001b[1m measurement \u001b[0m│\u001b[0m\n", + "├\u001b[0m───────────────\u001b[0m┼\u001b[0m────────────────────\u001b[0m┤\u001b[0m\n", + "│\u001b[0m cross_entropy \u001b[0m│\u001b[0m 0.8107153382628913 \u001b[0m│\u001b[0m\n", + "│\u001b[0m ZeroOneLoss \u001b[0m│\u001b[0m 0.4 \u001b[0m│\u001b[0m\n", + "└\u001b[0m───────────────\u001b[0m┴\u001b[0m────────────────────\u001b[0m┘\u001b[0m\n" + ] + }, + { + "data": { + "text/plain": [ + "(measure = Any[cross_entropy, ZeroOneLoss()],\n", + " measurement = [0.8107153382628913, 0.4],\n", + " per_fold = Array{Float64,1}[[0.44130929246809064, 1.2635805032959784, 0.6459172309118898, 0.8778906002819279, 0.8248790643565697], [0.5714285714285714, 0.2857142857142857, 0.2857142857142857, 0.5714285714285714, 0.2857142857142857]],\n", + " per_observation = Array{Array{Float64,1},1}[[[0.02469261259037141, 0.02469261259037141, 0.7537718023763802, 0.7537718023763802, 0.7537718023763802, 0.7537718023763802, 0.02469261259037141], [0.3483066942682157, 0.3483066942682157, 0.3483066942682157, 0.3483066942682157, 3.7135720667043075, 3.7135720667043075, 0.02469261259037141], [0.02469261259037141, 0.1823215567939546, 0.1823215567939546, 2.0149030205422647, 1.791759469228055, 0.1823215567939546, 0.1431008436406733], [1.3862943611198906, 1.3862943611198906, 1.3862943611198906, 0.2876820724517809, 0.02469261259037141, 0.2876820724517809, 1.3862943611198906], [0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 3.7135720667043075, 0.8109302162163288, 0.587786664902119, 0.587786664902119]], [[0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0], [1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0]]],)" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "evaluate!(tree, resampling=CV(nfolds=5, shuffle=true, rng=1234),\n", + " measure=[cross_entropy, ZeroOneLoss()])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With user-specified train/evaluation pairs of row indices:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[33mEvaluating over 3 folds: 100%[=========================] Time: 0:00:00\u001b[39m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌\u001b[0m───────────────\u001b[0m┬\u001b[0m─────────────────────\u001b[0m┐\u001b[0m\n", + "│\u001b[0m\u001b[1m measure \u001b[0m│\u001b[0m\u001b[1m measurement \u001b[0m│\u001b[0m\n", + "├\u001b[0m───────────────\u001b[0m┼\u001b[0m─────────────────────\u001b[0m┤\u001b[0m\n", + "│\u001b[0m cross_entropy \u001b[0m│\u001b[0m 0.895254695800462 \u001b[0m│\u001b[0m\n", + "│\u001b[0m ZeroOneLoss \u001b[0m│\u001b[0m 0.24136008918617616 \u001b[0m│\u001b[0m\n", + "└\u001b[0m───────────────\u001b[0m┴\u001b[0m─────────────────────\u001b[0m┘\u001b[0m\n" + ] + }, + { + "data": { + "text/plain": [ + "(measure = Any[cross_entropy, ZeroOneLoss()],\n", + " measurement = [0.895254695800462, 0.24136008918617616],\n", + " per_fold = Array{Float64,1}[[0.7538091986662944, 1.1473950551467866, 0.7845598335883047], [0.30434782608695654, 0.30434782608695654, 0.11538461538461539]],\n", + " per_observation = Array{Array{Float64,1},1}[[[0.15415067982725836, 0.15415067982725836, 0.15415067982725836, 0.15415067982725836, 0.15415067982725836, 1.9459101490553135, 0.15415067982725836, 0.02469261259037141, 1.9459101490553135, 1.9459101490553135 … 0.15415067982725836, 1.9459101490553135, 0.15415067982725836, 0.02469261259037141, 3.7135720667043075, 0.02469261259037141, 1.9459101490553135, 0.15415067982725836, 0.15415067982725836, 0.15415067982725836], [0.02469261259037141, 3.7135720667043075, 3.7135720667043075, 0.02469261259037141, 3.7135720667043075, 0.02469261259037141, 3.7135720667043075, 0.02469261259037141, 0.02469261259037141, 0.02469261259037141 … 0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 3.7135720667043075, 0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 0.02469261259037141], [0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 0.6931471805599453, 0.6931471805599453, 0.6931471805599453, 0.6931471805599453, 0.6931471805599453, 0.6931471805599453, 0.02469261259037141 … 0.02469261259037141, 0.6931471805599453, 3.7135720667043075, 0.02469261259037141, 0.6931471805599453, 0.6931471805599453, 3.7135720667043075, 3.7135720667043075, 0.02469261259037141, 0.6931471805599453]], [[0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0 … 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0]]],)" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "f1, f2, f3 = 1:13, 14:26, 27:36\n", + "pairs = [(f1, vcat(f2, f3)), (f2, vcat(f3, f1)), (f3, vcat(f1, f2))];\n", + "evaluate!(tree,\n", + " resampling=pairs,\n", + " measure=[cross_entropy, ZeroOneLoss()])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Changing a hyperparameter and re-evaluating:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[33mEvaluating over 5 folds: 100%[=========================] Time: 0:00:00\u001b[39m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "┌\u001b[0m───────────────\u001b[0m┬\u001b[0m─────────────────────\u001b[0m┐\u001b[0m\n", + "│\u001b[0m\u001b[1m measure \u001b[0m│\u001b[0m\u001b[1m measurement \u001b[0m│\u001b[0m\n", + "├\u001b[0m───────────────\u001b[0m┼\u001b[0m─────────────────────\u001b[0m┤\u001b[0m\n", + "│\u001b[0m cross_entropy \u001b[0m│\u001b[0m 0.7857788118033404 \u001b[0m│\u001b[0m\n", + "│\u001b[0m ZeroOneLoss \u001b[0m│\u001b[0m 0.37142857142857133 \u001b[0m│\u001b[0m\n", + "└\u001b[0m───────────────\u001b[0m┴\u001b[0m─────────────────────\u001b[0m┘\u001b[0m\n" + ] + }, + { + "data": { + "text/plain": [ + "(measure = Any[cross_entropy, ZeroOneLoss()],\n", + " measurement = [0.7857788118033404, 0.37142857142857133],\n", + " per_fold = Array{Float64,1}[[0.5192479199123463, 1.1617214839057737, 0.7334426224354447, 0.6982881261612496, 0.816193906601888], [0.42857142857142855, 0.2857142857142857, 0.2857142857142857, 0.5714285714285714, 0.2857142857142857]],\n", + " per_observation = Array{Array{Float64,1},1}[[[0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 1.1786549963416462, 1.1786549963416462, 1.1786549963416462, 0.02469261259037141], [0.6061358035703156, 0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 3.7135720667043075, 3.7135720667043075, 0.02469261259037141], [0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 3.7135720667043075, 1.0986122886681098, 0.02469261259037141, 0.2231435513142097], [0.9808292530117262, 0.9808292530117262, 0.9808292530117262, 0.4700036292457356, 0.02469261259037141, 0.4700036292457356, 0.9808292530117262], [0.02469261259037141, 0.02469261259037141, 0.02469261259037141, 3.7135720667043075, 1.252762968495368, 0.3364722366212129, 0.3364722366212129]], [[0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0], [1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0]]],)" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tree_model.max_depth = 3\n", + "evaluate!(tree,\n", + " resampling=CV(nfolds=5, shuffle=true, rng=1234),\n", + " measure=[cross_entropy, ZeroOneLoss()])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inspecting training results:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fit a ordinary least square model to some synthetic data:" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: Training \u001b[34mMachine{LinearRegressor} @ 7…80\u001b[39m.\n", + "└ @ MLJ /Users/anthony/Dropbox/Julia7/MLJ/MLJ/src/machines.jl:141\n" + ] + }, + { + "data": { + "text/plain": [ + "\u001b[34mMachine{LinearRegressor} @ 7…80\u001b[39m\n" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x1 = rand(100)\n", + "x2 = rand(100)\n", + "\n", + "X = (x1=x1, x2=x2)\n", + "y = x1 - 2x2 + 0.1*rand(100);\n", + "\n", + "ols_model = @load LinearRegressor pkg=GLM\n", + "ols = machine(ols_model, X, y)\n", + "fit!(ols)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get a named tuple representing the learned parameters,\n", + "human-readable if appropriate:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(coef = [0.9985128951528446, -1.9981845372437947],\n", + " intercept = 0.05141139704717806,)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fitted_params(ols)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get other training-related information:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(deviance = 0.08067317714592058,\n", + " dof_residual = 97.0,\n", + " stderror = [0.009386992893038402, 0.00995817861943297, 0.0073417739672351065],\n", + " vcov = [8.811563557395346e-5 -9.558303404671843e-6 -4.056936372724475e-5; -9.558303404671843e-6 9.916532141653193e-5 -4.6982822143496706e-5; -4.056936372724475e-5 -4.6982822143496706e-5 5.390164498597111e-5],)" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "report(ols)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic fit/transform for unsupervised models" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load data:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "([125, 100, 130, 9, 70, 148, 39, 64, 6, 107 … 134, 114, 52, 74, 44, 61, 83, 18, 122, 26], [97, 78, 30, 108, 101, 24, 85, 91, 135, 96 … 112, 144, 140, 72, 109, 41, 106, 147, 47, 5])" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X, y = @load_iris\n", + "train, test = partition(eachindex(y), 0.7, shuffle=true, rng=123)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instantiate and fit the model/machine:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: Training \u001b[34mMachine{PCA} @ 9…33\u001b[39m.\n", + "└ @ MLJ /Users/anthony/Dropbox/Julia7/MLJ/MLJ/src/machines.jl:141\n" + ] + }, + { + "data": { + "text/plain": [ + "\u001b[34mMachine{PCA} @ 9…33\u001b[39m\n" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@load PCA\n", + "pca_model = PCA(maxoutdim=2)\n", + "pca = machine(pca_model, X)\n", + "fit!(pca, rows=train)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Transform selected data bound to the machine:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "transform(pca, rows=test);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Transform new data:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(x1 = [4.819158264829177, 4.8208386973047, 5.111185670643473],\n", + " x2 = [-4.4441147103696315, -4.4288641941901625, -4.71503950609489],)" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Xnew = (sepal_length=rand(3), sepal_width=rand(3),\n", + " petal_length=rand(3), petal_width=rand(3));\n", + "transform(pca, Xnew)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inverting learned transformations" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: Training \u001b[34mMachine{UnivariateStandardizer} @ 9…82\u001b[39m.\n", + "└ @ MLJ /Users/anthony/Dropbox/Julia7/MLJ/MLJ/src/machines.jl:141\n" + ] + } + ], + "source": [ + "y = rand(100);\n", + "stand_model = UnivariateStandardizer()\n", + "stand = machine(stand_model, y)\n", + "fit!(stand)\n", + "z = transform(stand, y);\n", + "@assert inverse_transform(stand, z) ≈ y # true" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Nested hyperparameter tuning" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load data:" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(150×4 DataFrame\n", + "│ Row │ sepal_length │ sepal_width │ petal_length │ petal_width │\n", + "│ │ \u001b[90mFloat64\u001b[39m │ \u001b[90mFloat64\u001b[39m │ \u001b[90mFloat64\u001b[39m │ \u001b[90mFloat64\u001b[39m │\n", + "├─────┼──────────────┼─────────────┼──────────────┼─────────────┤\n", + "│ 1 │ 5.1 │ 3.5 │ 1.4 │ 0.2 │\n", + "│ 2 │ 4.9 │ 3.0 │ 1.4 │ 0.2 │\n", + "│ 3 │ 4.7 │ 3.2 │ 1.3 │ 0.2 │\n", + "│ 4 │ 4.6 │ 3.1 │ 1.5 │ 0.2 │\n", + "│ 5 │ 5.0 │ 3.6 │ 1.4 │ 0.2 │\n", + "│ 6 │ 5.4 │ 3.9 │ 1.7 │ 0.4 │\n", + "│ 7 │ 4.6 │ 3.4 │ 1.4 │ 0.3 │\n", + "│ 8 │ 5.0 │ 3.4 │ 1.5 │ 0.2 │\n", + "│ 9 │ 4.4 │ 2.9 │ 1.4 │ 0.2 │\n", + "│ 10 │ 4.9 │ 3.1 │ 1.5 │ 0.1 │\n", + "⋮\n", + "│ 140 │ 6.9 │ 3.1 │ 5.4 │ 2.1 │\n", + "│ 141 │ 6.7 │ 3.1 │ 5.6 │ 2.4 │\n", + "│ 142 │ 6.9 │ 3.1 │ 5.1 │ 2.3 │\n", + "│ 143 │ 5.8 │ 2.7 │ 5.1 │ 1.9 │\n", + "│ 144 │ 6.8 │ 3.2 │ 5.9 │ 2.3 │\n", + "│ 145 │ 6.7 │ 3.3 │ 5.7 │ 2.5 │\n", + "│ 146 │ 6.7 │ 3.0 │ 5.2 │ 2.3 │\n", + "│ 147 │ 6.3 │ 2.5 │ 5.0 │ 1.9 │\n", + "│ 148 │ 6.5 │ 3.0 │ 5.2 │ 2.0 │\n", + "│ 149 │ 6.2 │ 3.4 │ 5.4 │ 2.3 │\n", + "│ 150 │ 5.9 │ 3.0 │ 5.1 │ 1.8 │, CategoricalString{UInt32}[\"setosa\", \"setosa\", \"setosa\", \"setosa\", \"setosa\", \"setosa\", \"setosa\", \"setosa\", \"setosa\", \"setosa\" … \"virginica\", \"virginica\", \"virginica\", \"virginica\", \"virginica\", \"virginica\", \"virginica\", \"virginica\", \"virginica\", \"virginica\"])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "X, y = @load_iris" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define a model with nested hyperparameters:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: A model type \"DecisionTreeClassifier\" is already loaded. \n", + "│ No new code loaded. \n", + "└ @ MLJModels /Users/anthony/Dropbox/Julia7/MLJ/MLJModels/src/loading.jl:41\n" + ] + }, + { + "data": { + "text/plain": [ + "MLJ.ProbabilisticEnsembleModel(atom = DecisionTreeClassifier(pruning_purity = 1.0,\n", + " max_depth = -1,\n", + " min_samples_leaf = 1,\n", + " min_samples_split = 2,\n", + " min_purity_increase = 0.0,\n", + " n_subfeatures = 0,\n", + " display_depth = 5,\n", + " post_prune = false,\n", + " merge_purity_threshold = 0.9,\n", + " pdf_smoothing = 0.05,),\n", + " weights = Float64[],\n", + " bagging_fraction = 0.8,\n", + " rng = MersenneTwister(UInt32[0x71271325, 0x5861ba72, 0x34abacc2, 0x27102d83]),\n", + " n = 300,\n", + " parallel = true,\n", + " out_of_bag_measure = Any[],)\u001b[34m @ 8…22\u001b[39m" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tree_model = @load DecisionTreeClassifier\n", + "forest_model = EnsembleModel(atom=tree_model, n=300)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Inspect all hyperparameters, even nested ones (returns nested named tuple):" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(atom = (pruning_purity = 1.0,\n", + " max_depth = -1,\n", + " min_samples_leaf = 1,\n", + " min_samples_split = 2,\n", + " min_purity_increase = 0.0,\n", + " n_subfeatures = 0,\n", + " display_depth = 5,\n", + " post_prune = false,\n", + " merge_purity_threshold = 0.9,\n", + " pdf_smoothing = 0.05,),\n", + " weights = Float64[],\n", + " bagging_fraction = 0.8,\n", + " rng = MersenneTwister(UInt32[0x71271325, 0x5861ba72, 0x34abacc2, 0x27102d83]),\n", + " n = 300,\n", + " parallel = true,\n", + " out_of_bag_measure = Any[],)" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params(forest_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define ranges for hyperparameters to be tuned:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MLJ.NumericRange(field = :bagging_fraction,\n", + " lower = 0.5,\n", + " upper = 1.0,\n", + " scale = :log10,)\u001b[34m @ 1…28\u001b[39m" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "r1 = range(forest_model, :bagging_fraction, lower=0.5, upper=1.0, scale=:log10)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MLJ.NumericRange(field = :(atom.n_subfeatures),\n", + " lower = 1,\n", + " upper = 4,\n", + " scale = :linear,)\u001b[34m @ 1…75\u001b[39m" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "r2 = range(forest_model, :(atom.n_subfeatures), lower=1, upper=4) # nested" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wrap the model in a tuning strategy:" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MLJ.ProbabilisticTunedModel(model = MLJ.ProbabilisticEnsembleModel(atom = \u001b[34mDecisionTreeClassifier @ 1…80\u001b[39m,\n", + " weights = Float64[],\n", + " bagging_fraction = 0.8,\n", + " rng = MersenneTwister(UInt32[0x71271325, 0x5861ba72, 0x34abacc2, 0x27102d83]),\n", + " n = 300,\n", + " parallel = true,\n", + " out_of_bag_measure = Any[],),\n", + " tuning = Grid(resolution = 12,\n", + " parallel = true,),\n", + " resampling = CV(nfolds = 6,\n", + " shuffle = false,\n", + " rng = MersenneTwister(UInt32[0x71271325, 0x5861ba72, 0x34abacc2, 0x27102d83]),),\n", + " measure = MLJBase.CrossEntropy(),\n", + " weights = nothing,\n", + " operation = StatsBase.predict,\n", + " ranges = MLJ.NumericRange{T,Symbol} where T[\u001b[34mNumericRange @ 1…28\u001b[39m, \u001b[34mNumericRange @ 1…75\u001b[39m],\n", + " full_report = true,\n", + " train_best = true,)\u001b[34m @ 1…49\u001b[39m" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tuned_forest = TunedModel(model=forest_model,\n", + " tuning=Grid(resolution=12),\n", + " resampling=CV(nfolds=6),\n", + " ranges=[r1, r2],\n", + " measure=cross_entropy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bound the wrapped model to data:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\u001b[34mMachine{ProbabilisticTunedModel} @ 1…60\u001b[39m\n" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tuned = machine(tuned_forest, X, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fitting the resultant machine optimizes the hyperaparameters specified in\n", + "`range`, using the specified resampling strategy and performance\n", + "measure, and retrains on all data bound to the machine:" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Info: Training \u001b[34mMachine{ProbabilisticTunedModel} @ 1…60\u001b[39m.\n", + "└ @ MLJ /Users/anthony/Dropbox/Julia7/MLJ/MLJ/src/machines.jl:141\n", + "┌ Info: Mimimizing cross_entropy. \n", + "└ @ MLJ /Users/anthony/Dropbox/Julia7/MLJ/MLJ/src/tuning.jl:160\n", + "\u001b[33mIterating over a 48-point grid: 100%[=========================] Time: 0:00:40\u001b[39m\n", + "┌ Info: Training best model on all supplied data.\n", + "└ @ MLJ /Users/anthony/Dropbox/Julia7/MLJ/MLJ/src/tuning.jl:252\n" + ] + }, + { + "data": { + "text/plain": [ + "\u001b[34mMachine{ProbabilisticTunedModel} @ 1…60\u001b[39m\n" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fit!(tuned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Inspecting the optimal model:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(best_model = \u001b[34mProbabilisticEnsembleModel{DecisionTreeClassifier} @ 1…63\u001b[39m,)" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "F = fitted_params(tuned)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "MLJ.ProbabilisticEnsembleModel(atom = DecisionTreeClassifier(pruning_purity = 1.0,\n", + " max_depth = -1,\n", + " min_samples_leaf = 1,\n", + " min_samples_split = 2,\n", + " min_purity_increase = 0.0,\n", + " n_subfeatures = 3,\n", + " display_depth = 5,\n", + " post_prune = false,\n", + " merge_purity_threshold = 0.9,\n", + " pdf_smoothing = 0.05,),\n", + " weights = Float64[],\n", + " bagging_fraction = 0.5,\n", + " rng = MersenneTwister(UInt32[0x71271325, 0x5861ba72, 0x34abacc2, 0x27102d83]),\n", + " n = 300,\n", + " parallel = true,\n", + " out_of_bag_measure = Any[],)\u001b[34m @ 1…63\u001b[39m" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "F.best_model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Inspecting details of tuning procedure:" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(parameter_names = [\"bagging_fraction\" \"atom.n_subfeatures\"],\n", + " parameter_scales = Symbol[:log10 :linear],\n", + " parameter_values = Any[0.5 1; 0.5325205447199813 1; … ; 0.9389309106617063 4; 1.0 4],\n", + " measurements = [0.23836844761285972, 0.24310768116519496, 0.23155959227133427, 0.2358303191590729, 0.23388918367157183, 0.23944002555125055, 0.22931761600908399, 0.22924432030705047, 0.22621287086704908, 0.23123283225576788 … 0.1830737398891659, 0.19017188641338933, 0.2062563314942637, 0.2041996514962502, 0.210012168891926, 0.21305031478959782, 0.22735490003858747, 0.2359797272653158, 0.2584476524785048, 0.32572198859316304],\n", + " best_measurement = 0.17477371176810844,)" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "report(tuned)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To plot result of a 2D parameter tune, use `using Plots; pyplot();\n", + "plot(tuned)`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Predicting on new data using the optimized model:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Array{UnivariateFinite{String,UInt32,Float64},1}:\n", + " UnivariateFinite(setosa=>0.9677419354838652, versicolor=>0.01612903225806445, virginica=>0.01612903225806445)\n", + " UnivariateFinite(setosa=>0.9677419354838652, versicolor=>0.01612903225806445, virginica=>0.01612903225806445)\n", + " UnivariateFinite(setosa=>0.9677419354838652, versicolor=>0.01612903225806445, virginica=>0.01612903225806445)" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "predict(tuned, Xnew)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.2.0", + "language": "julia", + "name": "julia-1.2" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.2.0" + } + }, + "nbformat": 4, + "nbformat_minor": 3 +} From 3db4d9b68cdc21928429cd3c6fbccb854aac97cd Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Fri, 20 Sep 2019 08:58:04 +1200 Subject: [PATCH 10/11] fix doc generation --- docs/make.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index 97ba4618d..d0f495887 100755 --- a/docs/make.jl +++ b/docs/make.jl @@ -2,7 +2,7 @@ if Base.HOME_PROJECT[] !== nothing Base.HOME_PROJECT[] = abspath(Base.HOME_PROJECT[]) end using Pkg -# using Documenter +using Documenter using MLJ using MLJBase using MLJModels.Transformers From 2007631748455646f3ffab9e26944420c922f523 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Fri, 20 Sep 2019 11:15:39 +1200 Subject: [PATCH 11/11] typo in manual --- docs/src/common_mlj_workflows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/common_mlj_workflows.md b/docs/src/common_mlj_workflows.md index 3defc3e6a..7114ee40e 100644 --- a/docs/src/common_mlj_workflows.md +++ b/docs/src/common_mlj_workflows.md @@ -116,7 +116,7 @@ evaluate(model, X, y, resampling=CV(nfolds=5), measure=[rms, mav]) ```@example workflows using RDatasets vaso = dataset("robustbase", "vaso"); # a DataFrame -first(vasso, 3) +first(vaso, 3) ``` ```@example workflows