1.2.1 Data
Every fit, path and cross-validation procedure, and predict, takes its data in one of two ways: unnamed or named.
Unnamed data is the predictors, one row per observation and one column per predictor, with a separate response. The predictors are a math/matrix matrix, a list or vector of rows, each a list or vector, or a design matrix:
> (require math/matrix) > (define X (matrix [[1.0 2.0] [2.0 1.0] [3.0 4.0] [4.0 3.0] [5.0 6.0]])) > (define y '(1.2 3.9 3.1 5.8 5.1)) > (coef (ols X y)) '#(1.0816789548566557 1.8283186667839906 -0.858323423502696)
> (equal? (ols X y) (ols (matrix->list* X) y)) #t
A design matrix is a design-matrix? value: the predictors in the layout the solver reads, which every procedure converts its data to. Converting once yourself checks the data once, for many fits (see The explicit route).
The response has one entry per row: a list, a vector, an flvector, an f64vector, a math/array array or a Polars series. Its entries depend on the family:
Family |
| Response |
Gaussian |
| reals |
Binomial |
| 0/1, or two class labels: strings, symbols or booleans |
Multinomial |
| class numbers 0, …, K−1, every class present, or class labels |
Cox |
| positive times and, separately, 0/1 or boolean event indicators |
Poisson |
| non-negative counts |
Multi-response Gaussian |
| a matrix with one column per response, in any form of unnamed data |
Data is checked before the solver runs. Every numeric entry must be a finite real, every row the same length, and the response one entry per row; an error names the row and the column. R’s glmnet stops on a missing value too, but fits some infinite ones; here each is an error:
> (ols (matrix [[1.0 2.0] [2.0 +nan.0] [3.0 4.0]]) '(1 4 3)) ols: X has an element that is not finite
column: 1
row: 1
element: +nan.0
> (ols X '(1.0 2.0)) ols: y does not have one entry per row of X
length of y: 2
rows of X: 5
columns of X: 2
hint: rows are observations; is X transposed?
Class labels are all text (strings or symbols) or all booleans:
> (logistic-fit X '(yes no "yes" #t no) #:lambda 0.1) logistic-fit: contract violation
expected: a string or a symbol, as the first element is
given: #t
in: the element at position 3 of
the y argument of
(->*
(data/c
(response-for/c
X
(or/c 0 1)
#:classes?
#t)
#:lambda
(>=/c 0))
(#:predictors
(predictors-for/c X y #:classes? #t)
...)
logistic-result?)
contract from: <pkgs>/glmnet/core/lognet.rkt
blaming: program
(assuming the contract is correct)
at: <pkgs>/glmnet/core/lognet.rkt:33:3
1.2.1.1 Named data
Named data is a table, an association list or a hash from column names to columns, or a Polars dataframe. The second argument names the response column, and #:predictors, then required, the predictor columns. No other column is read:
> (define patients '((age 34 51 67 45 29) (dose 2.5 5.0 1.0 3.5 4.0) (response 3.1 5.2 1.9 4.0 4.4))) > (define by-name (ols patients "response" #:predictors '("age" "dose"))) > (coef by-name) '#(1.037012353177952 0.0003874059523250326 0.8329615305552988)
> (predict by-name '((dose 3.0) (age 40))) '(3.5513931829368497)
A fit from named data predicts from named data by column name, in any order. The Cox and multi-response families name several response columns (see Data arguments).
A formula, written with ~, names the response and the predictors in one expression, and keys the coefficients by name:
> (coef (formula-fit (~ response (+ age dose)) patients #:lambda 0.1))
'(("(Intercept)" . 1.2948504377976056)
("age" . 0.0)
("dose" . 0.7578592381882481))
Formulas and named data covers formulas, and Data where data comes from.