ts-classify 0.1.0 → 0.1.1
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/LICENSE.md +20 -0
- package/README.md +21 -118
- package/package.json +1 -1
- package/ts_classify_bg.wasm +0 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2026 Bart Riepe
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,123 +1,31 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ts-classify
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Fast text classification via SVM, compiled to WebAssembly.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
|
|
9
|
-
- **SMO** - O(N²), useful for kernel SVMs (future)
|
|
10
|
-
- **Multiclass classification**:
|
|
11
|
-
- **One-vs-Rest (OvR)** - K classifiers for K classes, fast prediction
|
|
12
|
-
- **One-vs-One (OvO)** - K(K-1)/2 classifiers, often more accurate
|
|
7
|
+
- **Multiclass classification** via One-vs-Rest (OvR) or One-vs-One (OvO)
|
|
8
|
+
- **Binary SVM** with coordinate descent solver (O(N) per pass)
|
|
13
9
|
- **Sparse vectors** - efficient for high-dimensional data (text, trigrams)
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **WebAssembly support** with JS-friendly API
|
|
10
|
+
- **Binary serialization** - train once, load instantly
|
|
11
|
+
- **Written in Rust**, compiled to WASM for near-native performance in the browser
|
|
17
12
|
|
|
18
13
|
## Installation
|
|
19
14
|
|
|
20
|
-
```toml
|
|
21
|
-
[dependencies]
|
|
22
|
-
svm = { path = "." }
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Usage
|
|
26
|
-
|
|
27
|
-
### Binary SVM
|
|
28
|
-
|
|
29
|
-
```rust
|
|
30
|
-
use svm::{SVM, SparseVec};
|
|
31
|
-
|
|
32
|
-
// Sparse format: Vec<(index, value)>
|
|
33
|
-
let samples: Vec<SparseVec> = vec![
|
|
34
|
-
vec![(0, -2.0), (1, 0.0)],
|
|
35
|
-
vec![(0, -1.0), (1, 1.0)],
|
|
36
|
-
vec![(0, 1.0), (1, 0.0)],
|
|
37
|
-
vec![(0, 2.0), (1, 1.0)],
|
|
38
|
-
];
|
|
39
|
-
let labels = vec![-1.0, -1.0, 1.0, 1.0];
|
|
40
|
-
|
|
41
|
-
let mut svm = SVM::new();
|
|
42
|
-
svm.train_sparse(&samples, &labels);
|
|
43
|
-
|
|
44
|
-
assert_eq!(svm.predict_sparse(&[(0, -3.0)]), -1.0);
|
|
45
|
-
assert_eq!(svm.predict_sparse(&[(0, 3.0)]), 1.0);
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Multiclass (One-vs-Rest)
|
|
49
|
-
|
|
50
|
-
```rust
|
|
51
|
-
use svm::{OneVsRestSVM, SparseVec};
|
|
52
|
-
|
|
53
|
-
let samples: Vec<SparseVec> = vec![
|
|
54
|
-
vec![(0, -2.0), (1, -2.0)], // class 0
|
|
55
|
-
vec![(0, 2.0), (1, -2.0)], // class 1
|
|
56
|
-
vec![(0, 0.0), (1, 2.0)], // class 2
|
|
57
|
-
// ... more samples
|
|
58
|
-
];
|
|
59
|
-
let labels = vec![0, 1, 2, /* ... */];
|
|
60
|
-
|
|
61
|
-
let mut svm = OneVsRestSVM::new();
|
|
62
|
-
svm.train_sparse(&samples, &labels);
|
|
63
|
-
|
|
64
|
-
let predicted_class = svm.predict_sparse(&[(0, 0.0), (1, 3.0)]);
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Custom Configuration
|
|
68
|
-
|
|
69
|
-
```rust
|
|
70
|
-
use svm::{SVM, TrainConfig, Solver};
|
|
71
|
-
|
|
72
|
-
let config = TrainConfig::coordinate_descent()
|
|
73
|
-
.with_c(0.5) // regularization (default: 1.0)
|
|
74
|
-
.with_max_iter(500) // max iterations (default: 1000)
|
|
75
|
-
.with_tol(0.001); // tolerance (default: 0.01)
|
|
76
|
-
|
|
77
|
-
let mut svm = SVM::new();
|
|
78
|
-
svm.train_sparse_with_config(&samples, &labels, &config);
|
|
79
|
-
|
|
80
|
-
// Or use SMO solver
|
|
81
|
-
let config = TrainConfig::smo()
|
|
82
|
-
.with_c(1.0)
|
|
83
|
-
.with_max_iter(10000);
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Serialization
|
|
87
|
-
|
|
88
|
-
```rust
|
|
89
|
-
// Save
|
|
90
|
-
let bytes = svm.to_bytes()?;
|
|
91
|
-
std::fs::write("model.bin", &bytes)?;
|
|
92
|
-
|
|
93
|
-
// Load
|
|
94
|
-
let bytes = std::fs::read("model.bin")?;
|
|
95
|
-
let svm = SVM::from_bytes(&bytes)?;
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## WebAssembly
|
|
99
|
-
|
|
100
|
-
Build for WASM (without parallel feature):
|
|
101
|
-
|
|
102
15
|
```bash
|
|
103
|
-
|
|
16
|
+
npm install ts-classify
|
|
104
17
|
```
|
|
105
18
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
wasm-pack build --target web --no-default-features
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### JavaScript API
|
|
19
|
+
## Usage
|
|
113
20
|
|
|
114
21
|
```javascript
|
|
115
|
-
import { JsOneVsRestSVM } from '
|
|
22
|
+
import init, { JsOneVsRestSVM } from 'ts-classify';
|
|
23
|
+
|
|
24
|
+
await init();
|
|
116
25
|
|
|
117
26
|
const svm = new JsOneVsRestSVM();
|
|
118
27
|
|
|
119
28
|
// Flat sparse format: [idx, val, idx, val, ...]
|
|
120
|
-
const sampleFlat = new Float64Array([0, -2.0, 1, 0.0]); // single sample
|
|
121
29
|
const samplesFlat = new Float64Array([
|
|
122
30
|
0, -2.0, 1, 0.0, // sample 0: 2 pairs
|
|
123
31
|
0, 1.0, 1, 1.0, // sample 1: 2 pairs
|
|
@@ -127,7 +35,7 @@ const labels = new Int32Array([0, 1]);
|
|
|
127
35
|
|
|
128
36
|
svm.train(samplesFlat, sampleLengths, labels);
|
|
129
37
|
|
|
130
|
-
const prediction = svm.predict(
|
|
38
|
+
const prediction = svm.predict(new Float64Array([0, -2.0, 1, 0.0]));
|
|
131
39
|
|
|
132
40
|
// Serialize/deserialize
|
|
133
41
|
const bytes = svm.to_bytes();
|
|
@@ -136,13 +44,6 @@ const loaded = JsOneVsRestSVM.from_bytes(bytes);
|
|
|
136
44
|
|
|
137
45
|
## Performance
|
|
138
46
|
|
|
139
|
-
Coordinate descent vs SMO on 50-class OvR:
|
|
140
|
-
|
|
141
|
-
| Solver | Train Time |
|
|
142
|
-
|--------|------------|
|
|
143
|
-
| Coordinate Descent | 6ms |
|
|
144
|
-
| SMO | 29s |
|
|
145
|
-
|
|
146
47
|
Scaling (coordinate descent, OvR):
|
|
147
48
|
|
|
148
49
|
| Classes | Classifiers | Train | Predict |
|
|
@@ -152,16 +53,18 @@ Scaling (coordinate descent, OvR):
|
|
|
152
53
|
| 100 | 100 | 1.4ms | 1.6µs |
|
|
153
54
|
| 5000 | 5000 | ~50-100ms | ~80µs |
|
|
154
55
|
|
|
155
|
-
##
|
|
56
|
+
## Building from source
|
|
156
57
|
|
|
157
|
-
|
|
58
|
+
Requires [Rust](https://rustup.rs/) and [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/).
|
|
158
59
|
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
|
|
60
|
+
```bash
|
|
61
|
+
wasm-pack build --target web --no-default-features
|
|
62
|
+
```
|
|
162
63
|
|
|
163
|
-
|
|
164
|
-
|
|
64
|
+
Run tests (native):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
cargo test --release
|
|
165
68
|
```
|
|
166
69
|
|
|
167
70
|
## License
|
package/package.json
CHANGED
package/ts_classify_bg.wasm
CHANGED
|
Binary file
|