fastlowess-wasm 3.0.0 → 3.1.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 +7 -316
- package/fastlowess_wasm_bg.wasm +0 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,21 +2,8 @@
|
|
|
2
2
|
# LOWESS Project
|
|
3
3
|
|
|
4
4
|
<p align="center">
|
|
5
|
-
<a href="https://crates.io/crates/lowess"><img src="https://img.shields.io/badge/lowess-000000?logo=rust&logoColor=white" alt="lowess"></a>
|
|
6
|
-
<a href="https://crates.io/crates/fastLowess"><img src="https://img.shields.io/badge/fastLowess-000000?logo=rust&logoColor=white" alt="fastLowess"></a>
|
|
7
|
-
<a href="https://pypi.org/project/fastlowess/"><img src="https://img.shields.io/badge/PyPI-3775A9?logo=pypi&logoColor=white" alt="PyPI"></a>
|
|
8
|
-
<a href="https://thisisamirv.r-universe.dev/rfastlowess"><img src="https://img.shields.io/badge/R--universe-276DC3?logo=r&logoColor=white" alt="R-universe"></a>
|
|
9
|
-
<a href="https://www.npmjs.com/package/fastlowess"><img src="https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white" alt="npm"></a>
|
|
10
|
-
<a href="https://juliahub.com/ui/Packages/General/FastLOWESS"><img src="https://img.shields.io/badge/Julia-9558B2?logo=julia&logoColor=white" alt="Julia"></a>
|
|
11
5
|
<a href="https://www.npmjs.com/package/fastlowess-wasm"><img src="https://img.shields.io/badge/WASM-654FF0?logo=webassembly&logoColor=white" alt="WASM"></a>
|
|
12
|
-
<a href="https://github.com/thisisamirv/lowess-project/
|
|
13
|
-
<br>
|
|
14
|
-
<a href="https://anaconda.org/conda-forge/fastlowess"><img src="https://img.shields.io/badge/fastlowess_(Python)-44A833?logo=anaconda&logoColor=white" alt="fastlowess (Python)"></a>
|
|
15
|
-
<a href="https://anaconda.org/conda-forge/libfastlowess"><img src="https://img.shields.io/badge/libfastlowess_(C++)-44A833?logo=anaconda&logoColor=white" alt="libfastlowess (C++)"></a>
|
|
16
|
-
<a href="https://anaconda.org/conda-forge/r-rfastlowess"><img src="https://img.shields.io/badge/rfastlowess_(R)-44A833?logo=anaconda&logoColor=white" alt="rfastlowess (R)"></a>
|
|
17
|
-
<br>
|
|
18
|
-
<a href="https://github.com/thisisamirv/lowess-project/actions/workflows/ci.yml"><img src="https://github.com/thisisamirv/lowess-project/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
19
|
-
<a href="https://github.com/ropensci/software-review/issues/769"><img src="https://badges.ropensci.org/769_status.svg" alt="Status at rOpenSci Software Peer Review"></a>
|
|
6
|
+
<a href="https://github.com/thisisamirv/lowess-project/actions/workflows/ci-wasm.yml"><img src="https://github.com/thisisamirv/lowess-project/actions/workflows/ci-wasm.yml/badge.svg" alt="CI"></a>
|
|
20
7
|
</p>
|
|
21
8
|
|
|
22
9
|
<p align="center">
|
|
@@ -27,18 +14,7 @@
|
|
|
27
14
|
|
|
28
15
|
The fastest, most robust, and most feature-complete language-agnostic LOWESS (Locally Weighted Scatterplot Smoothing) implementation for **Rust**, **Python**, **R**, **Julia**, **JavaScript**, **C++**, and **WebAssembly**.
|
|
29
16
|
|
|
30
|
-
|
|
31
|
-
>
|
|
32
|
-
> The `lowess-project` contains a complete ecosystem for LOWESS smoothing:
|
|
33
|
-
>
|
|
34
|
-
> - **[`lowess`](https://crates.io/crates/lowess)** - Core single-threaded Rust implementation with `no_std` support
|
|
35
|
-
> - **[`fastLowess`](https://crates.io/crates/fastLowess)** - Parallel CPU and GPU-accelerated Rust wrapper with ndarray integration
|
|
36
|
-
> - **[`R bindings`](https://thisisamirv.r-universe.dev/rfastlowess)** - extendr-based R binding
|
|
37
|
-
> - **[`Python bindings`](https://pypi.org/project/fastlowess/)** - PyO3-based Python binding
|
|
38
|
-
> - **[`Julia bindings`](https://juliahub.com/ui/Packages/General/FastLOWESS)** - Native Julia binding with C FFI
|
|
39
|
-
> - **[`JavaScript bindings`](https://www.npmjs.com/package/fastlowess)** - Node.js binding
|
|
40
|
-
> - **[`WebAssembly bindings`](https://www.npmjs.com/package/fastlowess-wasm)** - WASM binding
|
|
41
|
-
> - **[`C++ bindings`](https://github.com/thisisamirv/lowess-project/releases/latest)** - Native C++ binding with CMake integration
|
|
17
|
+
The `lowess-project` also offers bindings for Rust, Python, R, Julia, Node.js, WebAssembly, and C++ — see the [full repository](https://github.com/thisisamirv/lowess-project).
|
|
42
18
|
|
|
43
19
|
---
|
|
44
20
|
|
|
@@ -46,17 +22,13 @@ The fastest, most robust, and most feature-complete language-agnostic LOWESS (Lo
|
|
|
46
22
|
|
|
47
23
|
> [!NOTE]
|
|
48
24
|
>
|
|
49
|
-
> Currently available for R, Python, Rust, Julia, Node.js, WebAssembly, and C++. See the [Installation Guide](https://
|
|
50
|
-
|
|
51
|
-
### GPU Backend
|
|
52
|
-
|
|
53
|
-
In addition to `parallel = true` (multi-core CPU), the batch `Lowess` class in every binding — except WebAssembly — as well as the `fastLowess` Rust crate itself, can run on the GPU via `wgpu` (Vulkan/Metal/DX12). It's opt-in and worth enabling for high-throughput processing of large datasets (roughly 10k+ points); for smaller inputs the CPU backend is typically faster. `StreamingLowess`/`OnlineLowess` remain CPU-only. See the [GPU Backend guide](https://lowess.readthedocs.io/en/latest/user-guide/gpu-backend/) for installation instructions and usage.
|
|
25
|
+
> Currently available for R, Python, Rust, Julia, Node.js, WebAssembly, and C++. See the [Installation Guide](https://thisisamirv.github.io/lowess-project/wasm/installation/) for detailed installation instructions.
|
|
54
26
|
|
|
55
27
|
## Documentation
|
|
56
28
|
|
|
57
29
|
> [!NOTE]
|
|
58
30
|
>
|
|
59
|
-
> ### 📚 [View the full documentation](https://
|
|
31
|
+
> ### 📚 [View the full documentation](https://thisisamirv.github.io/lowess-project/wasm/)
|
|
60
32
|
|
|
61
33
|
---
|
|
62
34
|
|
|
@@ -80,7 +52,7 @@ In addition to `parallel = true` (multi-core CPU), the batch `Lowess` class in e
|
|
|
80
52
|
|
|
81
53
|
The `lowess` project beats the competition in terms of speed, whether in single-threaded or multi-threaded parallel execution. It is on average **200-327x faster** than Python's `statsmodels.lowess` and **2-3x faster** than R's `lowess`.
|
|
82
54
|
|
|
83
|
-
For more details on the performance comparison, see the [Benchmarks](https://
|
|
55
|
+
For more details on the performance comparison, see the [Benchmarks](https://thisisamirv.github.io/lowess-project/wasm/benchmarks/) page.
|
|
84
56
|
|
|
85
57
|
### Robustness
|
|
86
58
|
|
|
@@ -151,240 +123,6 @@ All implementations are **numerical twins** of R's `lowess`:
|
|
|
151
123
|
|
|
152
124
|
## API Reference
|
|
153
125
|
|
|
154
|
-
**R:**
|
|
155
|
-
|
|
156
|
-
```r
|
|
157
|
-
library(rfastlowess)
|
|
158
|
-
|
|
159
|
-
model <- Lowess(
|
|
160
|
-
fraction = 0.5,
|
|
161
|
-
iterations = 3L,
|
|
162
|
-
delta = 0.01,
|
|
163
|
-
weight_function = "tricube",
|
|
164
|
-
robustness_method = "bisquare",
|
|
165
|
-
scaling_method = "mad",
|
|
166
|
-
zero_weight_fallback = "use_local_mean",
|
|
167
|
-
boundary_policy = "extend",
|
|
168
|
-
confidence_intervals = 0.95,
|
|
169
|
-
prediction_intervals = 0.95,
|
|
170
|
-
return_diagnostics = TRUE,
|
|
171
|
-
return_residuals = TRUE,
|
|
172
|
-
return_robustness_weights = TRUE,
|
|
173
|
-
return_se = TRUE,
|
|
174
|
-
cv_fractions = c(0.3, 0.5, 0.7),
|
|
175
|
-
cv_method = "kfold",
|
|
176
|
-
cv_k = 5L,
|
|
177
|
-
cv_seed = 123L,
|
|
178
|
-
auto_converge = 1e-4,
|
|
179
|
-
parallel = TRUE
|
|
180
|
-
)
|
|
181
|
-
custom_weights <- rep(1, length(x))
|
|
182
|
-
result <- fit(model, x, y, custom_weights = custom_weights)
|
|
183
|
-
|
|
184
|
-
# Result structure:
|
|
185
|
-
result$x,
|
|
186
|
-
result$y,
|
|
187
|
-
result$standard_errors,
|
|
188
|
-
result$confidence_lower,
|
|
189
|
-
result$confidence_upper,
|
|
190
|
-
result$prediction_lower,
|
|
191
|
-
result$prediction_upper,
|
|
192
|
-
result$residuals,
|
|
193
|
-
result$robustness_weights,
|
|
194
|
-
result$diagnostics,
|
|
195
|
-
result$iterations_used,
|
|
196
|
-
result$fraction_used,
|
|
197
|
-
result$cv_scores
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
**Python:**
|
|
201
|
-
|
|
202
|
-
```python
|
|
203
|
-
from fastlowess import Lowess
|
|
204
|
-
|
|
205
|
-
model = Lowess(
|
|
206
|
-
fraction=0.5,
|
|
207
|
-
iterations=3,
|
|
208
|
-
delta=0.01,
|
|
209
|
-
weight_function="tricube",
|
|
210
|
-
robustness_method="bisquare",
|
|
211
|
-
scaling_method="mad",
|
|
212
|
-
zero_weight_fallback="use_local_mean",
|
|
213
|
-
boundary_policy="extend",
|
|
214
|
-
confidence_intervals=0.95,
|
|
215
|
-
prediction_intervals=0.95,
|
|
216
|
-
return_diagnostics=True,
|
|
217
|
-
return_residuals=True,
|
|
218
|
-
return_robustness_weights=True,
|
|
219
|
-
return_se=True,
|
|
220
|
-
cv_fractions=[0.3, 0.5, 0.7],
|
|
221
|
-
cv_method="kfold",
|
|
222
|
-
cv_k=5,
|
|
223
|
-
cv_seed=123,
|
|
224
|
-
auto_converge=1e-4,
|
|
225
|
-
parallel=True
|
|
226
|
-
)
|
|
227
|
-
custom_weights = [1.0] * len(x)
|
|
228
|
-
result = model.fit(x, y, custom_weights=custom_weights)
|
|
229
|
-
|
|
230
|
-
# Result structure:
|
|
231
|
-
result.x,
|
|
232
|
-
result.y,
|
|
233
|
-
result.standard_errors,
|
|
234
|
-
result.confidence_lower,
|
|
235
|
-
result.confidence_upper,
|
|
236
|
-
result.prediction_lower,
|
|
237
|
-
result.prediction_upper,
|
|
238
|
-
result.residuals,
|
|
239
|
-
result.robustness_weights,
|
|
240
|
-
result.diagnostics,
|
|
241
|
-
result.iterations_used,
|
|
242
|
-
result.fraction_used,
|
|
243
|
-
result.cv_scores
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
**Rust:**
|
|
247
|
-
|
|
248
|
-
```rust
|
|
249
|
-
use lowess::prelude::*;
|
|
250
|
-
|
|
251
|
-
let model = Lowess::new()
|
|
252
|
-
.fraction(0.5)
|
|
253
|
-
.iterations(3)
|
|
254
|
-
.delta(0.01)
|
|
255
|
-
.weight_function("tricube")
|
|
256
|
-
.robustness_method("bisquare")
|
|
257
|
-
.scaling_method("mad")
|
|
258
|
-
.zero_weight_fallback("use_local_mean")
|
|
259
|
-
.boundary_policy("extend")
|
|
260
|
-
.return_se()
|
|
261
|
-
.confidence_intervals(0.95)
|
|
262
|
-
.prediction_intervals(0.95)
|
|
263
|
-
.return_diagnostics()
|
|
264
|
-
.return_residuals()
|
|
265
|
-
.return_robustness_weights()
|
|
266
|
-
.cv_method("kfold")
|
|
267
|
-
.cv_k(5)
|
|
268
|
-
.cv_fractions(vec![0.3, 0.5, 0.7])
|
|
269
|
-
.cv_seed(123)
|
|
270
|
-
.auto_converge(1e-4)
|
|
271
|
-
.custom_weights(vec![1.0; x.len()])
|
|
272
|
-
.build()?;
|
|
273
|
-
|
|
274
|
-
let result = model.fit(&x, &y)?;
|
|
275
|
-
|
|
276
|
-
// Result structure:
|
|
277
|
-
pub struct LowessResult<T> {
|
|
278
|
-
pub x: Vec<T>, // Sorted x values
|
|
279
|
-
pub y: Vec<T>, // Smoothed y values
|
|
280
|
-
pub standard_errors: Option<Vec<T>>,
|
|
281
|
-
pub confidence_lower: Option<Vec<T>>,
|
|
282
|
-
pub confidence_upper: Option<Vec<T>>,
|
|
283
|
-
pub prediction_lower: Option<Vec<T>>,
|
|
284
|
-
pub prediction_upper: Option<Vec<T>>,
|
|
285
|
-
pub residuals: Option<Vec<T>>,
|
|
286
|
-
pub robustness_weights: Option<Vec<T>>,
|
|
287
|
-
pub diagnostics: Option<Diagnostics<T>>,
|
|
288
|
-
pub iterations_used: Option<usize>,
|
|
289
|
-
pub fraction_used: T,
|
|
290
|
-
pub cv_scores: Option<Vec<T>>,
|
|
291
|
-
}
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
**Julia:**
|
|
295
|
-
|
|
296
|
-
```julia
|
|
297
|
-
using FastLOWESS
|
|
298
|
-
|
|
299
|
-
model = Lowess(;
|
|
300
|
-
fraction=0.5,
|
|
301
|
-
iterations=3,
|
|
302
|
-
delta=NaN, # NaN for auto
|
|
303
|
-
weight_function="tricube",
|
|
304
|
-
robustness_method="bisquare",
|
|
305
|
-
scaling_method="mad",
|
|
306
|
-
zero_weight_fallback="use_local_mean",
|
|
307
|
-
boundary_policy="extend",
|
|
308
|
-
confidence_intervals=NaN,
|
|
309
|
-
prediction_intervals=NaN,
|
|
310
|
-
return_diagnostics=true,
|
|
311
|
-
return_residuals=true,
|
|
312
|
-
return_robustness_weights=true,
|
|
313
|
-
return_se=true,
|
|
314
|
-
cv_fractions=Float64[], # e.g. [0.3, 0.5]
|
|
315
|
-
cv_method="kfold",
|
|
316
|
-
cv_k=5,
|
|
317
|
-
cv_seed=123,
|
|
318
|
-
auto_converge=NaN,
|
|
319
|
-
parallel=true
|
|
320
|
-
)
|
|
321
|
-
custom_weights = ones(length(x))
|
|
322
|
-
result = fit(model, x, y; custom_weights=custom_weights)
|
|
323
|
-
|
|
324
|
-
# Result structure:
|
|
325
|
-
result.x,
|
|
326
|
-
result.y,
|
|
327
|
-
result.standard_errors,
|
|
328
|
-
result.confidence_lower,
|
|
329
|
-
result.confidence_upper,
|
|
330
|
-
result.prediction_lower,
|
|
331
|
-
result.prediction_upper,
|
|
332
|
-
result.residuals,
|
|
333
|
-
result.robustness_weights,
|
|
334
|
-
result.diagnostics,
|
|
335
|
-
result.iterations_used,
|
|
336
|
-
result.fraction_used,
|
|
337
|
-
result.cv_scores
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
**Node.js:**
|
|
341
|
-
|
|
342
|
-
```javascript
|
|
343
|
-
import { Lowess } from "fastlowess"
|
|
344
|
-
|
|
345
|
-
const model = new Lowess({
|
|
346
|
-
fraction: 0.5,
|
|
347
|
-
iterations: 3,
|
|
348
|
-
delta: 0.01,
|
|
349
|
-
weight_function: "tricube",
|
|
350
|
-
robustness_method: "bisquare",
|
|
351
|
-
scaling_method: "mad",
|
|
352
|
-
zero_weight_fallback: "use_local_mean",
|
|
353
|
-
boundary_policy: "extend",
|
|
354
|
-
return_se: true,
|
|
355
|
-
confidence_intervals: 0.95,
|
|
356
|
-
prediction_intervals: 0.95,
|
|
357
|
-
return_diagnostics: true,
|
|
358
|
-
return_residuals: true,
|
|
359
|
-
return_robustness_weights: true,
|
|
360
|
-
cv_fractions: [0.3, 0.5, 0.7],
|
|
361
|
-
cv_method: "kfold",
|
|
362
|
-
cv_k: 5,
|
|
363
|
-
cv_seed: 123,
|
|
364
|
-
auto_converge: 1e-4,
|
|
365
|
-
parallel: true
|
|
366
|
-
})
|
|
367
|
-
const custom_weights = Array(x.length).fill(1.0)
|
|
368
|
-
const result = model.fit(x, y, custom_weights)
|
|
369
|
-
|
|
370
|
-
// Result structure:
|
|
371
|
-
result.x,
|
|
372
|
-
result.y,
|
|
373
|
-
result.standard_errors,
|
|
374
|
-
result.confidence_lower,
|
|
375
|
-
result.confidence_upper,
|
|
376
|
-
result.prediction_lower,
|
|
377
|
-
result.prediction_upper,
|
|
378
|
-
result.residuals,
|
|
379
|
-
result.robustness_weights,
|
|
380
|
-
result.diagnostics,
|
|
381
|
-
result.iterations_used,
|
|
382
|
-
result.fraction_used,
|
|
383
|
-
result.cv_scores
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
**WebAssembly:**
|
|
387
|
-
|
|
388
126
|
```javascript
|
|
389
127
|
import { Lowess } from "fastlowess-wasm"
|
|
390
128
|
|
|
@@ -429,62 +167,15 @@ result.fraction_used,
|
|
|
429
167
|
result.cv_scores
|
|
430
168
|
```
|
|
431
169
|
|
|
432
|
-
**C++:**
|
|
433
|
-
|
|
434
|
-
```cpp
|
|
435
|
-
#include "fastlowess.hpp"
|
|
436
|
-
|
|
437
|
-
fastlowess::LowessOptions options;
|
|
438
|
-
options.fraction = 0.5;
|
|
439
|
-
options.iterations = 3;
|
|
440
|
-
options.delta = 0.01;
|
|
441
|
-
options.weight_function = "tricube";
|
|
442
|
-
options.robustness_method = "bisquare";
|
|
443
|
-
options.scaling_method = "mad";
|
|
444
|
-
options.zero_weight_fallback = "use_local_mean";
|
|
445
|
-
options.boundary_policy = "extend";
|
|
446
|
-
options.confidence_intervals = 0.95;
|
|
447
|
-
options.prediction_intervals = 0.95;
|
|
448
|
-
options.return_diagnostics = true;
|
|
449
|
-
options.return_residuals = true;
|
|
450
|
-
options.return_robustness_weights = true;
|
|
451
|
-
options.return_se = true;
|
|
452
|
-
options.cv_fractions = {0.3, 0.5, 0.7};
|
|
453
|
-
options.cv_method = "kfold";
|
|
454
|
-
options.cv_k = 5;
|
|
455
|
-
options.cv_seed = 123;
|
|
456
|
-
options.auto_converge = 1e-4;
|
|
457
|
-
options.parallel = true;
|
|
458
|
-
|
|
459
|
-
fastlowess::Lowess model(options);
|
|
460
|
-
std::vector<double> custom_weights(x.size(), 1.0);
|
|
461
|
-
const auto result = model.fit(x, y, custom_weights).value();
|
|
462
|
-
|
|
463
|
-
// Result structure:
|
|
464
|
-
result.x_vector(),
|
|
465
|
-
result.y_vector(),
|
|
466
|
-
result.standard_errors(),
|
|
467
|
-
result.confidence_lower(),
|
|
468
|
-
result.confidence_upper(),
|
|
469
|
-
result.prediction_lower(),
|
|
470
|
-
result.prediction_upper(),
|
|
471
|
-
result.residuals(),
|
|
472
|
-
result.robustness_weights(),
|
|
473
|
-
result.diagnostics(),
|
|
474
|
-
result.iterations_used(),
|
|
475
|
-
result.fraction_used(),
|
|
476
|
-
result.cv_scores()
|
|
477
|
-
```
|
|
478
|
-
|
|
479
170
|
---
|
|
480
171
|
|
|
481
172
|
## Contributing
|
|
482
173
|
|
|
483
|
-
Contributions are welcome! Please see
|
|
174
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](https://github.com/thisisamirv/lowess-project/blob/main/CONTRIBUTING.md) for more information.
|
|
484
175
|
|
|
485
176
|
## Changelog
|
|
486
177
|
|
|
487
|
-
See
|
|
178
|
+
See [CHANGELOG.md](https://github.com/thisisamirv/lowess-project/blob/main/CHANGELOG.md) for a history of changes.
|
|
488
179
|
|
|
489
180
|
## License
|
|
490
181
|
|
package/fastlowess_wasm_bg.wasm
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"Amir Valizadeh <thisisamirv@gmail.com>"
|
|
6
6
|
],
|
|
7
7
|
"description": "High-performance LOWESS (Locally Weighted Scatterplot Smoothing)",
|
|
8
|
-
"version": "3.
|
|
8
|
+
"version": "3.1.0",
|
|
9
9
|
"license": "MIT OR Apache-2.0",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -29,4 +29,4 @@
|
|
|
29
29
|
"regression",
|
|
30
30
|
"bioinformatics"
|
|
31
31
|
]
|
|
32
|
-
}
|
|
32
|
+
}
|