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.
Files changed (3) hide show
  1. package/README.md +341 -130
  2. package/linreg_core_bg.wasm +0 -0
  3. package/package.json +34 -34
package/README.md CHANGED
@@ -5,25 +5,27 @@
5
5
  [![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](LICENSE-MIT)
6
6
  [![Crates.io](https://img.shields.io/crates/v/linreg-core?color=orange)](https://crates.io/crates/linreg-core)
7
7
  [![docs.rs](https://img.shields.io/badge/docs.rs-linreg__core-green)](https://docs.rs/linreg-core)
8
+ [![PyPI](https://img.shields.io/badge/pypi-0.4.0-blue)](https://pypi.org/project/linreg-core/)
8
9
 
9
- ## Installation
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
- ```bash
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
- A lightweight, self-contained linear regression library written in Rust. Compiles to WebAssembly for browser use or runs as a native Rust crate.
16
+ ## Table of Contents
25
17
 
26
- **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.
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
- ### Dual Target
53
- - Browser (WASM) and server (native Rust)
54
- - Optional domain restriction for WASM builds
55
-
56
- ## Quick Start
54
+ ---
57
55
 
58
- ### Native Rust
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.3", default-features = false }
62
+ linreg-core = { version = "0.4", default-features = false }
65
63
  ```
66
64
 
67
- #### OLS Regression
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
- #### Ridge Regression
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
- #### Lasso Regression
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, // row 0: intercept, x1, x2
130
- 1.0, 2.0, 1.0, // row 1
131
- 1.0, 3.0, 1.5, // row 2
132
- 1.0, 4.0, 2.0, // row 3
133
- 1.0, 5.0, 2.5, // row 4
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() // uses default max_iter=1000, tol=1e-7
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
- #### Elastic Net Regression
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, // row 0: intercept, x1, x2
164
- 1.0, 2.0, 1.0, // row 1
165
- 1.0, 3.0, 1.5, // row 2
166
- 1.0, 4.0, 2.0, // row 3
167
- 1.0, 5.0, 2.5, // row 4
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
- ### WebAssembly (Browser)
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
- #### OLS in JavaScript
247
+ ### OLS Regression (WASM)
197
248
 
198
249
  ```javascript
199
- import init, { ols_regression } from 'linreg-core';
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
- #### Ridge Regression in JavaScript
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
- #### Lasso Regression in JavaScript
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
- #### Elastic Net Regression
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
- #### Lambda Path Generation
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
- ## Diagnostic Tests
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" // method: "r", "python", or "both"
363
+ "r"
351
364
  ));
352
365
 
353
- // White test - R-specific method (no method parameter)
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 (no method parameter)
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 (array of powers to test)
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 (1 = first-order autocorrelation)
420
+ 1, // order
408
421
  "chisq" // test_type: "chisq" or "f"
409
422
  ));
410
423
  ```
411
424
 
412
- ## Statistical Utilities (WASM)
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
- // Get library version
450
- const version = get_version(); // e.g., "0.3.0"
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
- // Verify WASM is working
453
- const msg = test(); // "Rust WASM is working!"
469
+ ```bash
470
+ LINREG_DOMAIN_RESTRICT=example.com,mysite.com wasm-pack build --release --target web
454
471
  ```
455
472
 
456
- ## Feature Flags
473
+ When NOT set (default), all domains are allowed.
457
474
 
458
- | Feature | Default | Description |
459
- |---------|---------|-------------|
460
- | `wasm` | Yes | Enables WASM bindings and browser support |
461
- | `validation` | No | Includes test data for validation tests |
475
+ ---
462
476
 
463
- For native Rust without WASM overhead:
477
+ ## Python Usage
464
478
 
465
- ```toml
466
- linreg-core = { version = "0.3", default-features = false }
479
+ Install from PyPI:
480
+
481
+ ```bash
482
+ pip install linreg-core
467
483
  ```
468
484
 
469
- ## Regularization Path
485
+ ### Quick Start (Python)
470
486
 
471
- Generate a sequence of lambda values for regularization path analysis:
487
+ The recommended way to use `linreg-core` in Python is with native types (lists or numpy arrays):
472
488
 
473
- ```rust,no_run
474
- use linreg_core::regularized::{make_lambda_path, LambdaPathOptions};
475
- use linreg_core::linalg::Matrix;
489
+ ```python
490
+ import linreg_core
476
491
 
477
- // Assume x is your standardized design matrix and y is centered
478
- let x = Matrix::new(100, 5, vec![0.0; 500]);
479
- let y = vec![0.0; 100];
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
- let options = LambdaPathOptions {
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
- let lambdas = make_lambda_path(&x, &y, &options, None, Some(0));
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
- // Use each lambda for cross-validation or plotting regularization paths
491
- for &lambda in lambdas.iter() {
492
- // Fit model with this lambda
493
- // ...
494
- }
504
+ # Get a formatted summary
505
+ print(result.summary())
495
506
  ```
496
507
 
497
- ## Domain Security (WASM)
508
+ **With NumPy arrays:**
498
509
 
499
- Optional domain restriction via build-time environment variable:
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
- LINREG_DOMAIN_RESTRICT=example.com,mysite.com wasm-pack build --release --target web
707
+ pip install linreg-core
503
708
  ```
504
709
 
505
- When NOT set (default), all domains are allowed. When set, only the specified domains can use the WASM module.
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).
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.3.0",
9
- "license": "MIT OR Apache-2.0",
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/jesse-anderson/linreg-core.git"
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://github.com/jesse-anderson/linreg-core#readme",
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
+ }