Skip to content

Commit dbce60b

Browse files
author
Ian
committed
Version bump
- Implemented T-SNE via the BHTSNE library as a preliminary dimensionality reduction technique
1 parent 4122d89 commit dbce60b

4 files changed

Lines changed: 116 additions & 5 deletions

File tree

Cargo.lock

Lines changed: 48 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "single_algebra"
3-
version = "0.8.7"
3+
version = "0.9.0"
44
edition = "2021"
55
license-file = "LICENSE.md"
66
description = "A linear algebra convenience library for the single-rust library. Can be used externally as well."
@@ -36,6 +36,7 @@ single-utilities = "0.8.5"
3636
linfa-tsne = {version = "0.7.1"}
3737
linfa = "0.7.1"
3838
single-svdlib = "1.0.6"
39+
bhtsne = "0.5.4"
3940

4041
[dev-dependencies]
4142
criterion = "0.7.0"

src/dimred/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@
1818
//! - Use **UMAP** (when available) for preserving both local and global structure in embeddings
1919
2020
pub mod pca;
21-
//pub mod tsne;
21+
pub mod tsne;

src/dimred/tsne/mod.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,66 @@
11
// Still working on that
2-
// Probably going to implement, either using Linfa_tsne or another approach
2+
// Probably going to implement, either using Linfa_tsne or another approach
3+
4+
use ndarray::{Array2, ArrayD, ArrayViewD};
5+
use single_utilities::traits::FloatOpsTS;
6+
7+
pub struct TSNEConfig {
8+
output_dim: u8,
9+
perplexity: f32,
10+
epochs: usize,
11+
theta: f32,
12+
}
13+
14+
pub fn run_f32<T: FloatOpsTS>(
15+
x: ArrayViewD<f32>,
16+
config: TSNEConfig,
17+
) -> anyhow::Result<ArrayD<f32>> {
18+
let n_obs = x.shape()[0];
19+
let n_dim = x.shape()[1];
20+
let x_slice = x.as_slice().unwrap();
21+
22+
let x_chunked_slice: Vec<&[f32]> = x_slice.chunks(n_dim).collect();
23+
let tsne_result = bhtsne::tSNE::new(&x_chunked_slice)
24+
.embedding_dim(config.output_dim)
25+
.perplexity(config.perplexity)
26+
.epochs(config.epochs)
27+
.barnes_hut(config.theta, |sample_a, sample_b| {
28+
sample_a
29+
.iter()
30+
.zip(sample_b.iter())
31+
.map(|(&a, &b)| num_traits::Float::powi(a - b, 2))
32+
.sum::<f32>()
33+
.sqrt()
34+
})
35+
.embedding();
36+
37+
let result = Array2::from_shape_vec((n_obs, config.output_dim as usize), tsne_result)?;
38+
Ok(result.into_dyn())
39+
}
40+
41+
pub fn run_f64<T: FloatOpsTS>(
42+
x: ArrayViewD<f64>,
43+
config: TSNEConfig,
44+
) -> anyhow::Result<ArrayD<f64>> {
45+
let n_obs = x.shape()[0];
46+
let n_dim = x.shape()[1];
47+
let x_slice = x.as_slice().unwrap();
48+
49+
let x_chunked_slice: Vec<&[f64]> = x_slice.chunks(n_dim).collect();
50+
let tsne_result = bhtsne::tSNE::new(&x_chunked_slice)
51+
.embedding_dim(config.output_dim)
52+
.perplexity(config.perplexity as f64)
53+
.epochs(config.epochs)
54+
.barnes_hut(config.theta as f64, |sample_a, sample_b| {
55+
sample_a
56+
.iter()
57+
.zip(sample_b.iter())
58+
.map(|(&a, &b)| num_traits::Float::powi(a - b, 2))
59+
.sum::<f64>()
60+
.sqrt()
61+
})
62+
.embedding();
63+
64+
let result = Array2::from_shape_vec((n_obs, config.output_dim as usize), tsne_result)?;
65+
Ok(result.into_dyn())
66+
}

0 commit comments

Comments
 (0)