Skip to content

Commit f8b3b94

Browse files
committed
add more doc improvements
1 parent 143f97a commit f8b3b94

File tree

9 files changed

+193
-39
lines changed

9 files changed

+193
-39
lines changed

README.md

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ A base Julia interface for machine learning and statistics
66
[![Build Status](https://github.com/JuliaAI/LearnAPI.jl/workflows/CI/badge.svg)](https://github.com/JuliaAI/LearnAPI.jl/actions)
77
[![codecov](https://codecov.io/gh/JuliaAI/LearnAPI.jl/graph/badge.svg?token=9IWT9KYINZ)](https://codecov.io/gh/JuliaAI/LearnAPI.jl?branch=dev)
88
[![Docs](https://img.shields.io/badge/docs-dev-blue.svg)](https://juliaai.github.io/LearnAPI.jl/dev/)
9-
10-
Comprehensive documentation is [here](https://juliaai.github.io/LearnAPI.jl/dev/).
9+
[![Docs](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliaai.github.io/LearnAPI.jl/stable/)
1110

1211
New contributions welcome. See the [road map](ROADMAP.md).
1312

@@ -24,13 +23,40 @@ predict(model, newdata)
2423
Here `learner` specifies the configuration the algorithm (the hyperparameters) while
2524
`model` stores learned parameters and any byproducts of algorithm execution.
2625

26+
LearnAPI.jl mostly a few method stubs and lots of documentation. It does not provide
27+
meta-algorithms, such as cross-validation or hyperparameter optimization, but does aim to
28+
support such algorithms.
29+
2730
## Related packages
2831

29-
- [MLCore.jl](https://github.com/JuliaML/MLCore.jl) ([docs](https://juliaml.github.io/MLCore.jl/stable/api/#Core-API))
32+
- [MLCore.jl](https://github.com/JuliaML/MLCore.jl): The default sub-sampling API (`getobs`/`numbobs`) for LearnAPI.jl implementations, which supports tables and arrays.
3033

3134
- [LearnTestAPI.jl](https://github.com/JuliaAI/LearnTestAPI.jl): Package to test implementations of LearnAPI.jl (but documented here)
3235

33-
- [LearnDataFrontEnds.jl](https://github.com/JuliaAI/LearnDataFrontEnds.jl): for including flexible, user-friendly, data front ends for LearnAPI.jl implementations ([docs](https://juliaai.github.io/stable/))
36+
- [LearnDataFrontEnds.jl](https://github.com/JuliaAI/LearnDataFrontEnds.jl): For including flexible, user-friendly, data front ends for LearnAPI.jl implementations ([docs](https://juliaai.github.io/stable/))
37+
38+
- [StatisticalMeasures.jl](https://github.com/JuliaAI/StatisticalMeasures.jl): Package providing metrics, compatible with LearnAPI.jl
39+
40+
### Selected packages providing alternative API's
41+
42+
The following alphabetical list of packages provide public base API's. Some provide
43+
additional functionality. PR's to add missing items very welcome.
44+
45+
- [AutoMLPipeline.jl](https://github.com/IBM/AutoMLPipeline.jl)
46+
47+
- [BetaML.jl](https://github.com/sylvaticus/BetaML.jl)
48+
49+
- [FastAI.jl](https://github.com/FluxML/FastAI.jl) (focused on deep learning)
50+
51+
- [LearnBase.jl](https://github.com/JuliaML/LearnBase.jl) (now archived but of historical interest)
52+
53+
- [MLJModelInterface.jl](https://github.com/JuliaAI/MLJModelInterface.jl)
54+
55+
- [ScikitLearn.jl](https://github.com/cstjean/ScikitLearn.jl) (an API in addition to being a wrapper for [scikit-learn](https://scikit-learn.org/stable/)
56+
57+
- [StatsAPI.jl](https://github.com/JuliaStats/StatsAPI.jl/blob/main/src/regressionmodel.jl) (specialized to needs of traditional statistical models)
58+
59+
- [MLUtils.jl](https://github.com/JuliaML/MLUtils.jl) (more than a base API, and focused on deep learning)
3460

3561

3662
## Credits

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ makedocs(
1717
"Anatomy of an Implementation" => "anatomy_of_an_implementation.md",
1818
"Reference" => [
1919
"Overview" => "reference.md",
20+
"Public Names" => "list_of_public_names.md",
2021
"fit/update" => "fit_update.md",
2122
"predict/transform" => "predict_transform.md",
2223
"Kinds of Target Proxy" => "kinds_of_target_proxy.md",

docs/src/anatomy_of_an_implementation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,8 @@ above. Here we must explicitly overload them, so that they also handle the outpu
555555

556556
```@example anatomy2
557557
LearnAPI.features(::Ridge, observations::RidgeFitObs) = observations.A
558-
LearnAPI.target(::Ridge, observations::RidgeFitObs) = observations.y
559558
LearnAPI.features(learner::Ridge, data) = LearnAPI.features(learner, obs(learner, data))
559+
LearnAPI.target(::Ridge, observations::RidgeFitObs) = observations.y
560560
LearnAPI.target(learner::Ridge, data) = LearnAPI.target(learner, obs(learner, data))
561561
```
562562

docs/src/examples.md

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ Below is the complete source code for the ridge implementations described in the
44
[Anatomy of an Implementation](@ref).
55

66
- [Basic implementation](@ref)
7-
- [Implementation with data front end](@ref)
7+
- [Implementation with a data front end](@ref)
8+
- [Implementation with a canned data front end](@ref)
89

910

1011
## Basic implementation
@@ -85,7 +86,7 @@ LearnAPI.strip(model::RidgeFitted) =
8586
LearnAPI.fit(learner::Ridge, X, y; kwargs...) = fit(learner, (X, y); kwargs...)
8687
```
8788

88-
# Implementation with data front end
89+
# Implementation with a data front end
8990

9091
```julia
9192
using LearnAPI
@@ -190,3 +191,91 @@ LearnAPI.strip(model::RidgeFitted) =
190191
)
191192

192193
```
194+
195+
# Implementation with a canned data front end
196+
197+
The following implements the `Saffron` data front end from
198+
[LearnDataFrontEnds.jl](https://juliaai.github.io/LearnDataFrontEnds.jl/stable/), which
199+
allows for a greater variety of forms of input to `fit` and `predict`. Refer to that
200+
package's [documentation](https://juliaai.github.io/LearnDataFrontEnds.jl/stable/) for details.
201+
202+
```julia
203+
using LearnAPI
204+
import LearnDataFrontEnds as FrontEnds
205+
using LinearAlgebra, Tables
206+
207+
struct Ridge{T<:Real}
208+
lambda::T
209+
end
210+
211+
Ridge(; lambda=0.1) = Ridge(lambda)
212+
213+
# struct for output of `fit`:
214+
struct RidgeFitted{T,F}
215+
learner::Ridge
216+
coefficients::Vector{T}
217+
named_coefficients::F
218+
end
219+
220+
frontend = FrontEnds.Saffron()
221+
222+
# these will return objects of type `FrontEnds.Obs`:
223+
LearnAPI.obs(learner::Ridge, data) = FrontEnds.fitobs(learner, data, frontend)
224+
LearnAPI.obs(model::RidgeFitted, data) = obs(model, data, frontend)
225+
226+
function LearnAPI.fit(learner::Ridge, observations::FrontEnds.Obs; verbosity=1)
227+
228+
lambda = learner.lambda
229+
230+
A = observations.features
231+
names = observations.names
232+
y = observations.target
233+
234+
# apply core learner:
235+
coefficients = (A*A' + learner.lambda*I)\(A*y) # 1 x p matrix
236+
237+
# determine named coefficients:
238+
named_coefficients = [names[j] => coefficients[j] for j in eachindex(names)]
239+
240+
# make some noise, if allowed:
241+
verbosity > 0 && @info "Coefficients: $named_coefficients"
242+
243+
return RidgeFitted(learner, coefficients, named_coefficients)
244+
245+
end
246+
LearnAPI.fit(learner::Ridge, data; kwargs...) =
247+
fit(learner, obs(learner, data); kwargs...)
248+
249+
LearnAPI.predict(model::RidgeFitted, ::Point, observations::FrontEnds.Obs) =
250+
(observations.features)'*model.coefficients
251+
LearnAPI.predict(model::RidgeFitted, ::Point, Xnew) =
252+
predict(model, Point(), obs(model, Xnew))
253+
254+
# training data deconstructors:
255+
LearnAPI.features(learner::Ridge, data) = LearnAPI.features(learner, data, frontend)
256+
LearnAPI.target(learner::Ridge, data) = LearnAPI.target(learner, data, frontend)
257+
258+
# accessor functions:
259+
LearnAPI.learner(model::RidgeFitted) = model.learner
260+
LearnAPI.coefficients(model::RidgeFitted) = model.named_coefficients
261+
LearnAPI.strip(model::RidgeFitted) =
262+
RidgeFitted(model.learner, model.coefficients, nothing)
263+
264+
@trait(
265+
Ridge,
266+
constructor = Ridge,
267+
kinds_of_proxy=(Point(),),
268+
tags = ("regression",),
269+
functions = (
270+
:(LearnAPI.fit),
271+
:(LearnAPI.learner),
272+
:(LearnAPI.clone),
273+
:(LearnAPI.strip),
274+
:(LearnAPI.obs),
275+
:(LearnAPI.features),
276+
:(LearnAPI.target),
277+
:(LearnAPI.predict),
278+
:(LearnAPI.coefficients),
279+
)
280+
)
281+
```

docs/src/index.md

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,14 @@ includes a number of Julia [traits](@ref traits) for promising specific behavior
2929

3030
LearnAPI.jl's has no package dependencies.
3131

32-
```@raw html
33-
&#128679;
34-
```
35-
36-
!!! warning
37-
38-
The API described here is under active development and not ready for adoption.
39-
Join an ongoing design discussion at
40-
[this](https://discourse.julialang.org/t/ann-learnapi-jl-proposal-for-a-basement-level-machine-learning-api/93048)
41-
Julia Discourse thread.
42-
4332

4433
## Sample workflow
4534

4635
Suppose `forest` is some object encapsulating the hyperparameters of the [random forest
4736
algorithm](https://en.wikipedia.org/wiki/Random_forest) (the number of trees, etc.). Then,
4837
a LearnAPI.jl interface can be implemented, for objects with the type of `forest`, to
4938
enable the basic workflow below. In this case data is presented following the
50-
"scikit-learn" `X, y` pattern, although LearnAPI.jl supports other data pattern.
39+
"scikit-learn" `X, y` pattern, although LearnAPI.jl supports other data patterns.
5140

5241
```julia
5342
# `X` is some training features
@@ -58,7 +47,7 @@ enable the basic workflow below. In this case data is presented following the
5847
@functions forest
5948

6049
# Train:
61-
model = fit(forest, X, y)
50+
model = fit(forest, (X, y))
6251

6352
# Generate point predictions:
6453
= predict(model, Xnew) # or `predict(model, Point(), Xnew)`
@@ -81,16 +70,16 @@ on the usual supervised/unsupervised learning dichotomy. From this point of view
8170
supervised learner is simply one in which a target variable exists, and happens to
8271
appear as an input to training but not to prediction.
8372

84-
## Data interfaces
73+
## Data interfaces and front ends
8574

8675
Algorithms are free to consume data in any format. However, a method called [`obs`](@ref
8776
data_interface) (read as "observations") gives developers the option of providing a
8877
separate data front end for their algorithms. In this case `obs` gives users and
8978
meta-algorithms access to an algorithm-specific representation of input data, which is
90-
additionally guaranteed to implement a standard interface for accessing individual observations,
91-
unless the algorithm explicitly opts out. Moreover, the `fit` and `predict` methods will
92-
also be able to consume these alternative data representations, for performance benefits
93-
in some situations.
79+
additionally guaranteed to implement a standard interface for accessing individual
80+
observations, unless the algorithm explicitly opts out. Moreover, the `fit` and `predict`
81+
methods can directly consume these alternative data representations, for performance
82+
benefits in some situations, such as cross-validation.
9483

9584
The fallback data interface is the [MLCore.jl](https://github.com/JuliaML/MLCore.jl)
9685
`getobs/numobs` interface (previously provided by MLUtils.jl) here tagged as

docs/src/list_of_public_names.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# List of Public Names
2+
3+
## Core methods
4+
5+
- [`fit`](@ref)
6+
7+
- [`update`](@ref)
8+
9+
- [`update_observations`](@ref)
10+
11+
- [`predict`](@ref)
12+
13+
- [`transform`](@ref)
14+
15+
- [`inverse_transform`](@ref)
16+
17+
- [`obs`](@ref)
18+
19+
## Training data deconstructors
20+
21+
- [`LearnAPI.features`](@ref)
22+
23+
- [`LearnAPI.target`](@ref)
24+
25+
- [`LearnAPI.weights`](@ref)
26+
27+
28+
## Accessor functions
29+
30+
See [here](@ref accessor_functions).
31+
32+
33+
## Learner traits
34+
35+
See [here](@ref traits).
36+
37+
38+
## Kinds of target proxy
39+
40+
See [here](@ref proxy_types).
41+
42+
43+
## Utilities (never overloaded)
44+
45+
- [`clone`](@ref): for cloning a learner with specified hyperparameter replacements.
46+
47+
- [`@trait`](@ref): for simultaneously declaring multiple traits
48+
49+
- [`@functions`](@ref): for listing functions available for use with a learner

docs/src/reference.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# [Reference](@id reference)
22

33
Here we give the definitive specification of the LearnAPI.jl interface. For informal
4-
guides see [Anatomy of an Implementation](@ref) and [Common Implementation
5-
Patterns](@ref patterns).
4+
guides see [Anatomy of an Implementation](@ref) and [Common Implementation Patterns](@ref
5+
patterns).
6+
7+
- [List of Public Names](@ref)
68

79

810
## [Important terms and concepts](@id scope)
@@ -190,7 +192,7 @@ Most learners will also implement [`predict`](@ref) and/or [`transform`](@ref).
190192

191193
- [`LearnAPI.features`](@ref input), [`LearnAPI.target`](@ref input),
192194
[`LearnAPI.weights`](@ref input): for extracting relevant parts of training data, where
193-
defined.
195+
defined. Also called *training data deconstructors*.
194196

195197
- [Accessor functions](@ref accessor_functions): these include functions like
196198
`LearnAPI.feature_importances` and `LearnAPI.training_losses`, for extracting, from

docs/src/testing_an_implementation.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
# Testing an Implementation
22

3-
Testing is provided by the LearnTestAPI.jl package documented below.
3+
Testing is provided by the LearnTestAPI.jl package documented below.
44

55
## Quick start
66

77
```@docs
88
LearnTestAPI
99
```
1010

11-
LearnAPI.jl and LearnTestAPI.jl have synchronized releases. For example, LearnTestAPI.jl
12-
version 0.2.3 will generally support all LearnAPI.jl versions 0.2.*.
13-
1411
!!! warning
1512

16-
New releases of LearnTestAPI.jl may add tests to `@testapi`, and this may result in
17-
new failures in client package test suites. Nevertheless, adding a test to `@testapi`
18-
is not considered a breaking change to LearnTestAPI, unless the addition supports a
19-
breaking release of LearnAPI.jl.
13+
New releases of LearnTestAPI.jl may add tests to `@testapi`, and
14+
this may result in new failures in client package test suites, because
15+
of previously undetected broken contracts. Adding a test to `@testapi`
16+
is not considered a breaking change
17+
to LearnTestAPI, unless it supports a breaking change to LearnAPI.jl.
2018

2119

2220
## The @testapi macro
@@ -28,7 +26,7 @@ LearnTestAPI.@testapi
2826
## Learners for testing
2927

3028
LearnTestAPI.jl provides some simple, tested, LearnAPI.jl implementations, which may be
31-
useful for testing learner wrappers and meta-algorithms.
29+
useful for testing learner wrappers and meta-algorithms.
3230

3331
```@docs
3432
LearnTestAPI.Ridge
@@ -44,7 +42,7 @@ LearnTestAPI.StumpRegressor
4442

4543
## Private methods
4644

47-
For LearnTestAPI.jl developers only, and subject to breaking changes:
45+
For LearnTestAPI.jl developers only, and subject to breaking changes at any time:
4846

4947
```@docs
5048
LearnTestAPI.@logged_testset

src/traits.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Return a tuple of expressions representing functions that can be meaningfully ap
6565
argument. Learner traits (methods for which `learner` is the *only* argument) are
6666
excluded.
6767
68-
To return actual functions, instead of symbols, use [`@functions`](@ref)` learner`
68+
To return actual functions, instead of symbols, use [`@functions`](@ref) `learner`
6969
instead.
7070
7171
The returned tuple may include expressions like `:(DecisionTree.print_tree)`, which

0 commit comments

Comments
 (0)