linreg-core 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +341 -130
- package/linreg_core_bg.wasm +0 -0
- package/package.json +34 -34
package/README.md
CHANGED
|
@@ -5,25 +5,27 @@
|
|
|
5
5
|
[](LICENSE-MIT)
|
|
6
6
|
[](https://crates.io/crates/linreg-core)
|
|
7
7
|
[](https://docs.rs/linreg-core)
|
|
8
|
+
[](https://pypi.org/project/linreg-core/)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
A lightweight, self-contained linear regression library written in Rust. Compiles to WebAssembly for browser use, Python bindings via PyO3, or runs as a native Rust crate.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
# npm
|
|
13
|
-
npm install linreg-core
|
|
14
|
-
|
|
15
|
-
# yarn
|
|
16
|
-
yarn add linreg-core
|
|
17
|
-
|
|
18
|
-
# pnpm
|
|
19
|
-
pnpm add linreg-core
|
|
20
|
-
```
|
|
12
|
+
**Key design principle:** All linear algebra and statistical distribution functions are implemented from scratch — no external math libraries required. This keeps binary sizes small and makes the crate highly portable.
|
|
21
13
|
|
|
22
14
|
---
|
|
23
15
|
|
|
24
|
-
|
|
16
|
+
## Table of Contents
|
|
25
17
|
|
|
26
|
-
|
|
18
|
+
| Section | Description |
|
|
19
|
+
|---------|-------------|
|
|
20
|
+
| [Features](#features) | Regression methods, model statistics, diagnostic tests |
|
|
21
|
+
| [Rust Usage](#rust-usage) | Native Rust crate usage |
|
|
22
|
+
| [WebAssembly Usage](#webassembly-usage) | Browser/JavaScript usage |
|
|
23
|
+
| [Python Usage](#python-usage) | Python bindings via PyO3 |
|
|
24
|
+
| [Feature Flags](#feature-flags) | Build configuration options |
|
|
25
|
+
| [Validation](#validation) | Testing and verification |
|
|
26
|
+
| [Implementation Notes](#implementation-notes) | Technical details |
|
|
27
|
+
|
|
28
|
+
---
|
|
27
29
|
|
|
28
30
|
## Features
|
|
29
31
|
|
|
@@ -49,22 +51,18 @@ A lightweight, self-contained linear regression library written in Rust. Compile
|
|
|
49
51
|
| **Autocorrelation** | Durbin-Watson, Breusch-Godfrey (higher-order) |
|
|
50
52
|
| **Influence** | Cook's Distance |
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
- Browser (WASM) and server (native Rust)
|
|
54
|
-
- Optional domain restriction for WASM builds
|
|
55
|
-
|
|
56
|
-
## Quick Start
|
|
54
|
+
---
|
|
57
55
|
|
|
58
|
-
|
|
56
|
+
## Rust Usage
|
|
59
57
|
|
|
60
58
|
Add to your `Cargo.toml`:
|
|
61
59
|
|
|
62
60
|
```toml
|
|
63
61
|
[dependencies]
|
|
64
|
-
linreg-core = { version = "0.
|
|
62
|
+
linreg-core = { version = "0.4", default-features = false }
|
|
65
63
|
```
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
### OLS Regression (Rust)
|
|
68
66
|
|
|
69
67
|
```rust
|
|
70
68
|
use linreg_core::core::ols_regression;
|
|
@@ -84,7 +82,7 @@ fn main() -> Result<(), linreg_core::Error> {
|
|
|
84
82
|
}
|
|
85
83
|
```
|
|
86
84
|
|
|
87
|
-
|
|
85
|
+
### Ridge Regression (Rust)
|
|
88
86
|
|
|
89
87
|
```rust,no_run
|
|
90
88
|
use linreg_core::regularized::{ridge_fit, RidgeFitOptions};
|
|
@@ -92,7 +90,6 @@ use linreg_core::linalg::Matrix;
|
|
|
92
90
|
|
|
93
91
|
fn main() -> Result<(), linreg_core::Error> {
|
|
94
92
|
let y = vec![2.5, 3.7, 4.2, 5.1, 6.3];
|
|
95
|
-
// Matrix: 5 rows × 2 cols (intercept + 1 predictor), row-major order
|
|
96
93
|
let x = Matrix::new(5, 2, vec![
|
|
97
94
|
1.0, 1.0, // row 0: intercept, x1
|
|
98
95
|
1.0, 2.0, // row 1
|
|
@@ -108,7 +105,6 @@ fn main() -> Result<(), linreg_core::Error> {
|
|
|
108
105
|
};
|
|
109
106
|
|
|
110
107
|
let result = ridge_fit(&x, &y, &options)?;
|
|
111
|
-
|
|
112
108
|
println!("Intercept: {}", result.intercept);
|
|
113
109
|
println!("Coefficients: {:?}", result.coefficients);
|
|
114
110
|
|
|
@@ -116,7 +112,7 @@ fn main() -> Result<(), linreg_core::Error> {
|
|
|
116
112
|
}
|
|
117
113
|
```
|
|
118
114
|
|
|
119
|
-
|
|
115
|
+
### Lasso Regression (Rust)
|
|
120
116
|
|
|
121
117
|
```rust,no_run
|
|
122
118
|
use linreg_core::regularized::{lasso_fit, LassoFitOptions};
|
|
@@ -124,24 +120,22 @@ use linreg_core::linalg::Matrix;
|
|
|
124
120
|
|
|
125
121
|
fn main() -> Result<(), linreg_core::Error> {
|
|
126
122
|
let y = vec![2.5, 3.7, 4.2, 5.1, 6.3];
|
|
127
|
-
// Matrix: 5 rows × 3 cols (intercept + 2 predictors), row-major order
|
|
128
123
|
let x = Matrix::new(5, 3, vec![
|
|
129
|
-
1.0, 1.0, 0.5,
|
|
130
|
-
1.0, 2.0, 1.0,
|
|
131
|
-
1.0, 3.0, 1.5,
|
|
132
|
-
1.0, 4.0, 2.0,
|
|
133
|
-
1.0, 5.0, 2.5,
|
|
124
|
+
1.0, 1.0, 0.5,
|
|
125
|
+
1.0, 2.0, 1.0,
|
|
126
|
+
1.0, 3.0, 1.5,
|
|
127
|
+
1.0, 4.0, 2.0,
|
|
128
|
+
1.0, 5.0, 2.5,
|
|
134
129
|
]);
|
|
135
130
|
|
|
136
131
|
let options = LassoFitOptions {
|
|
137
132
|
lambda: 0.1,
|
|
138
133
|
standardize: true,
|
|
139
134
|
intercept: true,
|
|
140
|
-
..Default::default()
|
|
135
|
+
..Default::default()
|
|
141
136
|
};
|
|
142
137
|
|
|
143
138
|
let result = lasso_fit(&x, &y, &options)?;
|
|
144
|
-
|
|
145
139
|
println!("Intercept: {}", result.intercept);
|
|
146
140
|
println!("Coefficients: {:?}", result.coefficients);
|
|
147
141
|
println!("Non-zero coefficients: {}", result.n_nonzero);
|
|
@@ -150,7 +144,7 @@ fn main() -> Result<(), linreg_core::Error> {
|
|
|
150
144
|
}
|
|
151
145
|
```
|
|
152
146
|
|
|
153
|
-
|
|
147
|
+
### Elastic Net Regression (Rust)
|
|
154
148
|
|
|
155
149
|
```rust,no_run
|
|
156
150
|
use linreg_core::regularized::{elastic_net_fit, ElasticNetOptions};
|
|
@@ -158,13 +152,12 @@ use linreg_core::linalg::Matrix;
|
|
|
158
152
|
|
|
159
153
|
fn main() -> Result<(), linreg_core::Error> {
|
|
160
154
|
let y = vec![2.5, 3.7, 4.2, 5.1, 6.3];
|
|
161
|
-
// Matrix: 5 rows × 3 cols (intercept + 2 predictors), row-major order
|
|
162
155
|
let x = Matrix::new(5, 3, vec![
|
|
163
|
-
1.0, 1.0, 0.5,
|
|
164
|
-
1.0, 2.0, 1.0,
|
|
165
|
-
1.0, 3.0, 1.5,
|
|
166
|
-
1.0, 4.0, 2.0,
|
|
167
|
-
1.0, 5.0, 2.5,
|
|
156
|
+
1.0, 1.0, 0.5,
|
|
157
|
+
1.0, 2.0, 1.0,
|
|
158
|
+
1.0, 3.0, 1.5,
|
|
159
|
+
1.0, 4.0, 2.0,
|
|
160
|
+
1.0, 5.0, 2.5,
|
|
168
161
|
]);
|
|
169
162
|
|
|
170
163
|
let options = ElasticNetOptions {
|
|
@@ -176,7 +169,6 @@ fn main() -> Result<(), linreg_core::Error> {
|
|
|
176
169
|
};
|
|
177
170
|
|
|
178
171
|
let result = elastic_net_fit(&x, &y, &options)?;
|
|
179
|
-
|
|
180
172
|
println!("Intercept: {}", result.intercept);
|
|
181
173
|
println!("Coefficients: {:?}", result.coefficients);
|
|
182
174
|
println!("Non-zero coefficients: {}", result.n_nonzero);
|
|
@@ -185,7 +177,66 @@ fn main() -> Result<(), linreg_core::Error> {
|
|
|
185
177
|
}
|
|
186
178
|
```
|
|
187
179
|
|
|
188
|
-
###
|
|
180
|
+
### Diagnostic Tests (Rust)
|
|
181
|
+
|
|
182
|
+
```rust
|
|
183
|
+
use linreg_core::diagnostics::{
|
|
184
|
+
breusch_pagan_test, durbin_watson_test, jarque_bera_test,
|
|
185
|
+
shapiro_wilk_test, RainbowMethod, rainbow_test
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
fn main() -> Result<(), linreg_core::Error> {
|
|
189
|
+
let y = vec![/* your data */];
|
|
190
|
+
let x = vec![vec![/* predictor 1 */], vec![/* predictor 2 */]];
|
|
191
|
+
|
|
192
|
+
// Heteroscedasticity
|
|
193
|
+
let bp = breusch_pagan_test(&y, &x)?;
|
|
194
|
+
println!("Breusch-Pagan: LM={:.4}, p={:.4}", bp.statistic, bp.p_value);
|
|
195
|
+
|
|
196
|
+
// Autocorrelation
|
|
197
|
+
let dw = durbin_watson_test(&y, &x)?;
|
|
198
|
+
println!("Durbin-Watson: {:.4}", dw.statistic);
|
|
199
|
+
|
|
200
|
+
// Normality
|
|
201
|
+
let jb = jarque_bera_test(&y, &x)?;
|
|
202
|
+
println!("Jarque-Bera: JB={:.4}, p={:.4}", jb.statistic, jb.p_value);
|
|
203
|
+
|
|
204
|
+
// Linearity
|
|
205
|
+
let rainbow = rainbow_test(&y, &x, 0.5, RainbowMethod::R)?;
|
|
206
|
+
println!("Rainbow: F={:.4}, p={:.4}",
|
|
207
|
+
rainbow.r_result.as_ref().unwrap().statistic,
|
|
208
|
+
rainbow.r_result.as_ref().unwrap().p_value);
|
|
209
|
+
|
|
210
|
+
Ok(())
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Lambda Path Generation (Rust)
|
|
215
|
+
|
|
216
|
+
```rust,no_run
|
|
217
|
+
use linreg_core::regularized::{make_lambda_path, LambdaPathOptions};
|
|
218
|
+
use linreg_core::linalg::Matrix;
|
|
219
|
+
|
|
220
|
+
let x = Matrix::new(100, 5, vec![0.0; 500]);
|
|
221
|
+
let y = vec![0.0; 100];
|
|
222
|
+
|
|
223
|
+
let options = LambdaPathOptions {
|
|
224
|
+
nlambda: 100,
|
|
225
|
+
lambda_min_ratio: Some(0.01),
|
|
226
|
+
alpha: 1.0, // Lasso
|
|
227
|
+
..Default::default()
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
let lambdas = make_lambda_path(&x, &y, &options, None, Some(0));
|
|
231
|
+
|
|
232
|
+
for &lambda in lambdas.iter() {
|
|
233
|
+
// Fit model with this lambda
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## WebAssembly Usage
|
|
189
240
|
|
|
190
241
|
Build with wasm-pack:
|
|
191
242
|
|
|
@@ -193,10 +244,10 @@ Build with wasm-pack:
|
|
|
193
244
|
wasm-pack build --release --target web
|
|
194
245
|
```
|
|
195
246
|
|
|
196
|
-
|
|
247
|
+
### OLS Regression (WASM)
|
|
197
248
|
|
|
198
249
|
```javascript
|
|
199
|
-
import init, { ols_regression } from '
|
|
250
|
+
import init, { ols_regression } from './pkg/linreg_core.js';
|
|
200
251
|
|
|
201
252
|
async function run() {
|
|
202
253
|
await init();
|
|
@@ -219,7 +270,7 @@ async function run() {
|
|
|
219
270
|
run();
|
|
220
271
|
```
|
|
221
272
|
|
|
222
|
-
|
|
273
|
+
### Ridge Regression (WASM)
|
|
223
274
|
|
|
224
275
|
```javascript
|
|
225
276
|
const result = JSON.parse(ridge_regression(
|
|
@@ -233,7 +284,7 @@ const result = JSON.parse(ridge_regression(
|
|
|
233
284
|
console.log("Coefficients:", result.coefficients);
|
|
234
285
|
```
|
|
235
286
|
|
|
236
|
-
|
|
287
|
+
### Lasso Regression (WASM)
|
|
237
288
|
|
|
238
289
|
```javascript
|
|
239
290
|
const result = JSON.parse(lasso_regression(
|
|
@@ -250,7 +301,7 @@ console.log("Coefficients:", result.coefficients);
|
|
|
250
301
|
console.log("Non-zero coefficients:", result.n_nonzero);
|
|
251
302
|
```
|
|
252
303
|
|
|
253
|
-
|
|
304
|
+
### Elastic Net Regression (WASM)
|
|
254
305
|
|
|
255
306
|
```javascript
|
|
256
307
|
const result = JSON.parse(elastic_net_regression(
|
|
@@ -268,7 +319,7 @@ console.log("Coefficients:", result.coefficients);
|
|
|
268
319
|
console.log("Non-zero coefficients:", result.n_nonzero);
|
|
269
320
|
```
|
|
270
321
|
|
|
271
|
-
|
|
322
|
+
### Lambda Path Generation (WASM)
|
|
272
323
|
|
|
273
324
|
```javascript
|
|
274
325
|
const path = JSON.parse(make_lambda_path(
|
|
@@ -282,45 +333,7 @@ console.log("Lambda sequence:", path.lambda_path);
|
|
|
282
333
|
console.log("Lambda max:", path.lambda_max);
|
|
283
334
|
```
|
|
284
335
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
### Native Rust
|
|
288
|
-
|
|
289
|
-
```rust
|
|
290
|
-
use linreg_core::diagnostics::{
|
|
291
|
-
breusch_pagan_test, durbin_watson_test, jarque_bera_test,
|
|
292
|
-
shapiro_wilk_test, RainbowMethod, rainbow_test
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
fn main() -> Result<(), linreg_core::Error> {
|
|
296
|
-
let y = vec![/* your data */];
|
|
297
|
-
let x = vec![vec![/* predictor 1 */], vec![/* predictor 2 */]];
|
|
298
|
-
|
|
299
|
-
// Heteroscedasticity
|
|
300
|
-
let bp = breusch_pagan_test(&y, &x)?;
|
|
301
|
-
println!("Breusch-Pagan: LM={:.4}, p={:.4}", bp.statistic, bp.p_value);
|
|
302
|
-
|
|
303
|
-
// Autocorrelation
|
|
304
|
-
let dw = durbin_watson_test(&y, &x)?;
|
|
305
|
-
println!("Durbin-Watson: {:.4}", dw.statistic);
|
|
306
|
-
|
|
307
|
-
// Normality
|
|
308
|
-
let jb = jarque_bera_test(&y, &x)?;
|
|
309
|
-
println!("Jarque-Bera: JB={:.4}, p={:.4}", jb.statistic, jb.p_value);
|
|
310
|
-
|
|
311
|
-
// Linearity
|
|
312
|
-
let rainbow = rainbow_test(&y, &x, 0.5, RainbowMethod::R)?;
|
|
313
|
-
println!("Rainbow: F={:.4}, p={:.4}",
|
|
314
|
-
rainbow.r_result.as_ref().unwrap().statistic,
|
|
315
|
-
rainbow.r_result.as_ref().unwrap().p_value);
|
|
316
|
-
|
|
317
|
-
Ok(())
|
|
318
|
-
}
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### WebAssembly
|
|
322
|
-
|
|
323
|
-
All diagnostic tests are available in WASM:
|
|
336
|
+
### Diagnostic Tests (WASM)
|
|
324
337
|
|
|
325
338
|
```javascript
|
|
326
339
|
// Rainbow test
|
|
@@ -347,16 +360,16 @@ const bp = JSON.parse(breusch_pagan_test(
|
|
|
347
360
|
const white = JSON.parse(white_test(
|
|
348
361
|
JSON.stringify(y),
|
|
349
362
|
JSON.stringify(x),
|
|
350
|
-
"r"
|
|
363
|
+
"r"
|
|
351
364
|
));
|
|
352
365
|
|
|
353
|
-
// White test - R-specific method
|
|
366
|
+
// White test - R-specific method
|
|
354
367
|
const whiteR = JSON.parse(r_white_test(
|
|
355
368
|
JSON.stringify(y),
|
|
356
369
|
JSON.stringify(x)
|
|
357
370
|
));
|
|
358
371
|
|
|
359
|
-
// White test - Python-specific method
|
|
372
|
+
// White test - Python-specific method
|
|
360
373
|
const whitePy = JSON.parse(python_white_test(
|
|
361
374
|
JSON.stringify(y),
|
|
362
375
|
JSON.stringify(x)
|
|
@@ -396,7 +409,7 @@ const cd = JSON.parse(cooks_distance_test(
|
|
|
396
409
|
const reset = JSON.parse(reset_test(
|
|
397
410
|
JSON.stringify(y),
|
|
398
411
|
JSON.stringify(x),
|
|
399
|
-
JSON.stringify([2, 3]), // powers
|
|
412
|
+
JSON.stringify([2, 3]), // powers
|
|
400
413
|
"fitted" // type: "fitted", "regressor", or "princomp"
|
|
401
414
|
));
|
|
402
415
|
|
|
@@ -404,12 +417,12 @@ const reset = JSON.parse(reset_test(
|
|
|
404
417
|
const bg = JSON.parse(breusch_godfrey_test(
|
|
405
418
|
JSON.stringify(y),
|
|
406
419
|
JSON.stringify(x),
|
|
407
|
-
1, // order
|
|
420
|
+
1, // order
|
|
408
421
|
"chisq" // test_type: "chisq" or "f"
|
|
409
422
|
));
|
|
410
423
|
```
|
|
411
424
|
|
|
412
|
-
|
|
425
|
+
### Statistical Utilities (WASM)
|
|
413
426
|
|
|
414
427
|
```javascript
|
|
415
428
|
// Student's t CDF: P(T <= t)
|
|
@@ -436,7 +449,6 @@ const correlation = JSON.parse(stats_correlation(
|
|
|
436
449
|
### CSV Parsing (WASM)
|
|
437
450
|
|
|
438
451
|
```javascript
|
|
439
|
-
// Parse CSV content - returns headers, data rows, and numeric column names
|
|
440
452
|
const csv = parse_csv(csvContent);
|
|
441
453
|
const parsed = JSON.parse(csv);
|
|
442
454
|
console.log("Headers:", parsed.headers);
|
|
@@ -446,63 +458,256 @@ console.log("Numeric columns:", parsed.numeric_columns);
|
|
|
446
458
|
### Helper Functions (WASM)
|
|
447
459
|
|
|
448
460
|
```javascript
|
|
449
|
-
//
|
|
450
|
-
const
|
|
461
|
+
const version = get_version(); // e.g., "0.4.0"
|
|
462
|
+
const msg = test(); // "Rust WASM is working!"
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Domain Security (WASM)
|
|
466
|
+
|
|
467
|
+
Optional domain restriction via build-time environment variable:
|
|
451
468
|
|
|
452
|
-
|
|
453
|
-
|
|
469
|
+
```bash
|
|
470
|
+
LINREG_DOMAIN_RESTRICT=example.com,mysite.com wasm-pack build --release --target web
|
|
454
471
|
```
|
|
455
472
|
|
|
456
|
-
|
|
473
|
+
When NOT set (default), all domains are allowed.
|
|
457
474
|
|
|
458
|
-
|
|
459
|
-
|---------|---------|-------------|
|
|
460
|
-
| `wasm` | Yes | Enables WASM bindings and browser support |
|
|
461
|
-
| `validation` | No | Includes test data for validation tests |
|
|
475
|
+
---
|
|
462
476
|
|
|
463
|
-
|
|
477
|
+
## Python Usage
|
|
464
478
|
|
|
465
|
-
|
|
466
|
-
|
|
479
|
+
Install from PyPI:
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
pip install linreg-core
|
|
467
483
|
```
|
|
468
484
|
|
|
469
|
-
|
|
485
|
+
### Quick Start (Python)
|
|
470
486
|
|
|
471
|
-
|
|
487
|
+
The recommended way to use `linreg-core` in Python is with native types (lists or numpy arrays):
|
|
472
488
|
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
use linreg_core::linalg::Matrix;
|
|
489
|
+
```python
|
|
490
|
+
import linreg_core
|
|
476
491
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
492
|
+
# Works with Python lists
|
|
493
|
+
y = [1, 2, 3, 4, 5]
|
|
494
|
+
x = [[1, 2, 3, 4, 5]]
|
|
495
|
+
names = ["Intercept", "X1"]
|
|
480
496
|
|
|
481
|
-
|
|
482
|
-
nlambda: 100,
|
|
483
|
-
lambda_min_ratio: Some(0.01),
|
|
484
|
-
alpha: 1.0, // Lasso
|
|
485
|
-
..Default::default()
|
|
486
|
-
};
|
|
497
|
+
result = linreg_core.ols_regression(y, x, names)
|
|
487
498
|
|
|
488
|
-
|
|
499
|
+
# Access attributes directly
|
|
500
|
+
print(f"R²: {result.r_squared}")
|
|
501
|
+
print(f"Coefficients: {result.coefficients}")
|
|
502
|
+
print(f"F-statistic: {result.f_statistic}")
|
|
489
503
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
// Fit model with this lambda
|
|
493
|
-
// ...
|
|
494
|
-
}
|
|
504
|
+
# Get a formatted summary
|
|
505
|
+
print(result.summary())
|
|
495
506
|
```
|
|
496
507
|
|
|
497
|
-
|
|
508
|
+
**With NumPy arrays:**
|
|
498
509
|
|
|
499
|
-
|
|
510
|
+
```python
|
|
511
|
+
import numpy as np
|
|
512
|
+
import linreg_core
|
|
513
|
+
|
|
514
|
+
y = np.array([1, 2, 3, 4, 5])
|
|
515
|
+
x = np.array([[1, 2, 3, 4, 5]])
|
|
516
|
+
|
|
517
|
+
result = linreg_core.ols_regression(y, x, ["Intercept", "X1"])
|
|
518
|
+
print(result.summary())
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**Result objects** provide:
|
|
522
|
+
- Direct attribute access (`result.r_squared`, `result.coefficients`)
|
|
523
|
+
- `summary()` method for formatted output
|
|
524
|
+
- `to_dict()` method for JSON serialization
|
|
525
|
+
|
|
526
|
+
### OLS Regression (Python)
|
|
527
|
+
|
|
528
|
+
```python
|
|
529
|
+
import linreg_core
|
|
530
|
+
|
|
531
|
+
y = [1, 2, 3, 4, 5]
|
|
532
|
+
x = [[1, 2, 3, 4, 5]]
|
|
533
|
+
names = ["Intercept", "X1"]
|
|
534
|
+
|
|
535
|
+
result = linreg_core.ols_regression(y, x, names)
|
|
536
|
+
print(f"Coefficients: {result.coefficients}")
|
|
537
|
+
print(f"R-squared: {result.r_squared}")
|
|
538
|
+
print(f"F-statistic: {result.f_statistic}")
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Ridge Regression (Python)
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
result = linreg_core.ridge_regression(
|
|
545
|
+
y, x, ["Intercept", "X1"],
|
|
546
|
+
1.0, # lambda
|
|
547
|
+
True # standardize
|
|
548
|
+
)
|
|
549
|
+
print(f"Intercept: {result.intercept}")
|
|
550
|
+
print(f"Coefficients: {result.coefficients}")
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Lasso Regression (Python)
|
|
554
|
+
|
|
555
|
+
```python
|
|
556
|
+
result = linreg_core.lasso_regression(
|
|
557
|
+
y, x, ["Intercept", "X1"],
|
|
558
|
+
0.1, # lambda
|
|
559
|
+
True, # standardize
|
|
560
|
+
100000, # max_iter
|
|
561
|
+
1e-7 # tol
|
|
562
|
+
)
|
|
563
|
+
print(f"Intercept: {result.intercept}")
|
|
564
|
+
print(f"Coefficients: {result.coefficients}")
|
|
565
|
+
print(f"Non-zero: {result.n_nonzero}")
|
|
566
|
+
print(f"Converged: {result.converged}")
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Elastic Net Regression (Python)
|
|
570
|
+
|
|
571
|
+
```python
|
|
572
|
+
result = linreg_core.elastic_net_regression(
|
|
573
|
+
y, x, ["Intercept", "X1"],
|
|
574
|
+
0.1, # lambda
|
|
575
|
+
0.5, # alpha (0 = Ridge, 1 = Lasso, 0.5 = balanced)
|
|
576
|
+
True, # standardize
|
|
577
|
+
100000, # max_iter
|
|
578
|
+
1e-7 # tol
|
|
579
|
+
)
|
|
580
|
+
print(f"Intercept: {result.intercept}")
|
|
581
|
+
print(f"Coefficients: {result.coefficients}")
|
|
582
|
+
print(f"Non-zero: {result.n_nonzero}")
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### Lambda Path Generation (Python)
|
|
586
|
+
|
|
587
|
+
```python
|
|
588
|
+
path = linreg_core.make_lambda_path(
|
|
589
|
+
y, x,
|
|
590
|
+
100, # n_lambda
|
|
591
|
+
0.01 # lambda_min_ratio
|
|
592
|
+
)
|
|
593
|
+
print(f"Lambda max: {path.lambda_max}")
|
|
594
|
+
print(f"Lambda min: {path.lambda_min}")
|
|
595
|
+
print(f"Number: {path.n_lambda}")
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Diagnostic Tests (Python)
|
|
599
|
+
|
|
600
|
+
```python
|
|
601
|
+
# Breusch-Pagan test (heteroscedasticity)
|
|
602
|
+
bp = linreg_core.breusch_pagan_test(y, x)
|
|
603
|
+
print(f"Statistic: {bp.statistic}, p-value: {bp.p_value}")
|
|
604
|
+
|
|
605
|
+
# Harvey-Collier test (linearity)
|
|
606
|
+
hc = linreg_core.harvey_collier_test(y, x)
|
|
607
|
+
|
|
608
|
+
# Rainbow test (linearity) - supports "r", "python", or "both" methods
|
|
609
|
+
rainbow = linreg_core.rainbow_test(y, x, 0.5, "r")
|
|
610
|
+
|
|
611
|
+
# White test - choose method: "r", "python", or "both"
|
|
612
|
+
white = linreg_core.white_test(y, x, "r")
|
|
613
|
+
# Or use specific method functions
|
|
614
|
+
white_r = linreg_core.r_white_test(y, x)
|
|
615
|
+
white_py = linreg_core.python_white_test(y, x)
|
|
616
|
+
|
|
617
|
+
# Jarque-Bera test (normality)
|
|
618
|
+
jb = linreg_core.jarque_bera_test(y, x)
|
|
619
|
+
|
|
620
|
+
# Durbin-Watson test (autocorrelation)
|
|
621
|
+
dw = linreg_core.durbin_watson_test(y, x)
|
|
622
|
+
print(f"DW statistic: {dw.statistic}")
|
|
623
|
+
|
|
624
|
+
# Shapiro-Wilk test (normality)
|
|
625
|
+
sw = linreg_core.shapiro_wilk_test(y, x)
|
|
626
|
+
|
|
627
|
+
# Anderson-Darling test (normality)
|
|
628
|
+
ad = linreg_core.anderson_darling_test(y, x)
|
|
629
|
+
|
|
630
|
+
# Cook's Distance (influential observations)
|
|
631
|
+
cd = linreg_core.cooks_distance_test(y, x)
|
|
632
|
+
print(f"Influential points: {cd.influential_4_over_n}")
|
|
633
|
+
|
|
634
|
+
# RESET test (model specification)
|
|
635
|
+
reset = linreg_core.reset_test(y, x, [2, 3], "fitted")
|
|
636
|
+
|
|
637
|
+
# Breusch-Godfrey test (higher-order autocorrelation)
|
|
638
|
+
bg = linreg_core.breusch_godfrey_test(y, x, 1, "chisq")
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### Statistical Utilities (Python)
|
|
642
|
+
|
|
643
|
+
```python
|
|
644
|
+
# Student's t CDF
|
|
645
|
+
t_cdf = linreg_core.get_t_cdf(1.96, 20)
|
|
646
|
+
|
|
647
|
+
# Critical t-value (two-tailed)
|
|
648
|
+
t_crit = linreg_core.get_t_critical(0.05, 20)
|
|
649
|
+
|
|
650
|
+
# Normal inverse CDF (probit)
|
|
651
|
+
z_score = linreg_core.get_normal_inverse(0.975)
|
|
652
|
+
|
|
653
|
+
# Library version
|
|
654
|
+
version = linreg_core.get_version()
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### Descriptive Statistics (Python)
|
|
658
|
+
|
|
659
|
+
```python
|
|
660
|
+
import numpy as np
|
|
661
|
+
|
|
662
|
+
# All return float directly (no parsing needed)
|
|
663
|
+
mean = linreg_core.stats_mean([1, 2, 3, 4, 5])
|
|
664
|
+
variance = linreg_core.stats_variance([1, 2, 3, 4, 5])
|
|
665
|
+
stddev = linreg_core.stats_stddev([1, 2, 3, 4, 5])
|
|
666
|
+
median = linreg_core.stats_median([1, 2, 3, 4, 5])
|
|
667
|
+
quantile = linreg_core.stats_quantile([1, 2, 3, 4, 5], 0.5)
|
|
668
|
+
correlation = linreg_core.stats_correlation([1, 2, 3, 4, 5], [2, 4, 6, 8, 10])
|
|
669
|
+
|
|
670
|
+
# Works with numpy arrays too
|
|
671
|
+
mean = linreg_core.stats_mean(np.array([1, 2, 3, 4, 5]))
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### CSV Parsing (Python)
|
|
675
|
+
|
|
676
|
+
```python
|
|
677
|
+
csv_content = '''name,value,category
|
|
678
|
+
Alice,42.5,A
|
|
679
|
+
Bob,17.3,B
|
|
680
|
+
Charlie,99.9,A'''
|
|
681
|
+
|
|
682
|
+
result = linreg_core.parse_csv(csv_content)
|
|
683
|
+
print(f"Headers: {result.headers}")
|
|
684
|
+
print(f"Numeric columns: {result.numeric_columns}")
|
|
685
|
+
print(f"Data rows: {result.n_rows}")
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
690
|
+
## Feature Flags
|
|
691
|
+
|
|
692
|
+
| Feature | Default | Description |
|
|
693
|
+
|---------|---------|-------------|
|
|
694
|
+
| `wasm` | Yes | Enables WASM bindings and browser support |
|
|
695
|
+
| `python` | No | Enables Python bindings via PyO3 |
|
|
696
|
+
| `validation` | No | Includes test data for validation tests |
|
|
697
|
+
|
|
698
|
+
For native Rust without WASM overhead:
|
|
699
|
+
|
|
700
|
+
```toml
|
|
701
|
+
linreg-core = { version = "0.4", default-features = false }
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
For Python bindings (built with maturin):
|
|
500
705
|
|
|
501
706
|
```bash
|
|
502
|
-
|
|
707
|
+
pip install linreg-core
|
|
503
708
|
```
|
|
504
709
|
|
|
505
|
-
|
|
710
|
+
---
|
|
506
711
|
|
|
507
712
|
## Validation
|
|
508
713
|
|
|
@@ -521,6 +726,8 @@ wasm-pack test --node
|
|
|
521
726
|
cargo test --all-features
|
|
522
727
|
```
|
|
523
728
|
|
|
729
|
+
---
|
|
730
|
+
|
|
524
731
|
## Implementation Notes
|
|
525
732
|
|
|
526
733
|
### Regularization
|
|
@@ -546,10 +753,14 @@ minimize (1/(2n)) * Σ(yᵢ - β₀ - xᵢᵀβ)² + λ * [(1 - α) * ||β||₂
|
|
|
546
753
|
- Shapiro-Wilk limited to n <= 5000 (matching R's limitation)
|
|
547
754
|
- White test may differ from R on collinear datasets due to numerical precision in near-singular matrices
|
|
548
755
|
|
|
756
|
+
---
|
|
757
|
+
|
|
549
758
|
## Disclaimer
|
|
550
759
|
|
|
551
760
|
This library is under active development and has not reached 1.0 stability. While outputs are validated against R and Python implementations, **do not use this library for critical applications** (medical, financial, safety-critical systems) without independent verification. See the [LICENSE](LICENSE-MIT) for full terms. The software is provided "as is" without warranty of any kind.
|
|
552
761
|
|
|
762
|
+
---
|
|
763
|
+
|
|
553
764
|
## License
|
|
554
765
|
|
|
555
766
|
Dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE).
|
package/linreg_core_bg.wasm
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "linreg-core",
|
|
3
|
-
"type": "module",
|
|
4
|
-
"collaborators": [
|
|
5
|
-
"Jesse Anderson"
|
|
6
|
-
],
|
|
7
|
-
"description": "Lightweight linear regression (OLS, Ridge, Lasso, Elastic Net) with diagnostic tests. Pure Rust - no external math dependencies.",
|
|
8
|
-
"version": "0.
|
|
9
|
-
"license": "MIT OR Apache-2.0",
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"linreg_core_bg.wasm",
|
|
16
|
-
"linreg_core.js",
|
|
17
|
-
"linreg_core.d.ts",
|
|
18
|
-
"LICENSE-APACHE",
|
|
19
|
-
"LICENSE-MIT"
|
|
20
|
-
],
|
|
21
|
-
"main": "linreg_core.js",
|
|
22
|
-
"homepage": "https://
|
|
23
|
-
"types": "linreg_core.d.ts",
|
|
24
|
-
"sideEffects": [
|
|
25
|
-
"./snippets/*"
|
|
26
|
-
],
|
|
27
|
-
"keywords": [
|
|
28
|
-
"regression",
|
|
29
|
-
"statistics",
|
|
30
|
-
"linear-regression",
|
|
31
|
-
"ridge",
|
|
32
|
-
"lasso"
|
|
33
|
-
]
|
|
34
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "linreg-core",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"collaborators": [
|
|
5
|
+
"Jesse Anderson"
|
|
6
|
+
],
|
|
7
|
+
"description": "Lightweight linear regression (OLS, Ridge, Lasso, Elastic Net) with diagnostic tests. Pure Rust - no external math dependencies.",
|
|
8
|
+
"version": "0.4.0",
|
|
9
|
+
"license": "MIT OR Apache-2.0",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/jesse-anderson/linreg-core"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"linreg_core_bg.wasm",
|
|
16
|
+
"linreg_core.js",
|
|
17
|
+
"linreg_core.d.ts",
|
|
18
|
+
"LICENSE-APACHE",
|
|
19
|
+
"LICENSE-MIT"
|
|
20
|
+
],
|
|
21
|
+
"main": "linreg_core.js",
|
|
22
|
+
"homepage": "https://jesse-anderson.net",
|
|
23
|
+
"types": "linreg_core.d.ts",
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"./snippets/*"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"regression",
|
|
29
|
+
"statistics",
|
|
30
|
+
"linear-regression",
|
|
31
|
+
"ridge",
|
|
32
|
+
"lasso"
|
|
33
|
+
]
|
|
34
|
+
}
|