Skip to main content

ExprMatrix

Struct ExprMatrix 

Source
pub struct ExprMatrix { /* private fields */ }
Expand description

An expression matrix with named rows (features/genes) and columns (samples).

Element (row i, col j) is stored at data[i * ncol + j]. Missing values are represented as f64::NAN (the analog of R’s NA).

Implementations§

Source§

impl ExprMatrix

Source

pub fn new( row_names: Vec<String>, col_names: Vec<String>, data: Vec<f64>, ) -> Self

Build a matrix from row names, column names, and row-major data.

Panics if data.len() != row_names.len() * col_names.len().

Examples found in repository?
examples/quickstart.rs (line 39)
10fn main() {
11    // 6 genes (rows) x 3 samples (cols), log2-scale expression, stored row-major.
12    // Five are MCP-counter markers; GAPDH is a non-marker housekeeping gene and
13    // is ignored, exactly as in R (markers are matched by name against the
14    // bundled signature).
15    let genes = vec![
16        "CD3D".to_string(),  // T cells
17        "CD28".to_string(),  // T cells
18        "CD8B".to_string(),  // CD8 T cells
19        "CD19".to_string(),  // B lineage
20        "CD79A".to_string(), // B lineage
21        "GAPDH".to_string(), // not a marker -> ignored
22    ];
23    let samples = vec![
24        "tumor_A".to_string(),
25        "tumor_B".to_string(),
26        "normal".to_string(),
27    ];
28    #[rustfmt::skip]
29    let data = vec![
30        //  tumor_A  tumor_B  normal
31            8.1,     7.4,     2.0, // CD3D
32            7.6,     7.1,     1.8, // CD28
33            6.9,     6.2,     1.5, // CD8B
34            4.2,     8.3,     2.1, // CD19
35            4.0,     8.0,     1.9, // CD79A
36           11.0,    11.1,    11.0, // GAPDH (flat housekeeping)
37    ];
38
39    let expr = ExprMatrix::new(genes, samples, data);
40    let result = mcp_counter(&expr, FeaturesType::HugoSymbols);
41
42    // Each score is the mean of a population's present markers. Populations with
43    // no present markers are dropped (as in R); the rest appear in MCP-counter's
44    // signature order: T cells, CD8 T cells, B lineage.
45    print!("{:<14}", "population");
46    for s in &result.samples {
47        print!("{s:>10}");
48    }
49    println!();
50    for (p, pop) in result.populations.iter().enumerate() {
51        print!("{pop:<14}");
52        for s in 0..result.samples.len() {
53            print!("{:>10.3}", result.score(p, s));
54        }
55        println!();
56    }
57}
Source

pub fn nrow(&self) -> usize

Number of rows (features).

Examples found in repository?
examples/parity_realdata.rs (line 84)
78fn main() {
79    let dir = PathBuf::from(DATA_DIR);
80
81    // --- MCP-counter on human racle (HUGO symbols) ---
82    let mcp_expr = read_tsv_matrix(&read_dump(&dir.join("mcp_real_input.tsv")));
83    let mcp_exp = read_dump(&dir.join("mcp_real_expected.tsv"));
84    let mcp_genes = mcp_expr.nrow();
85    let mcp_res = mcp_counter(&mcp_expr, FeaturesType::HugoSymbols);
86    let mcp_worst = worst_rel_err(&mcp_res, &mcp_exp);
87
88    // --- mMCP-counter on mouse petitprez (Gene.Symbol, GCRm39) ---
89    let mmcp_expr = read_tsv_matrix(&read_dump(&dir.join("mmcp_real_input.tsv")));
90    let mmcp_exp = read_dump(&dir.join("mmcp_real_expected.tsv"));
91    let mmcp_genes = mmcp_expr.nrow();
92    let mmcp_res = mmcp_counter(
93        &mmcp_expr,
94        MurineFeaturesType::GeneSymbol,
95        GenomeVersion::GCRm39,
96    );
97    let mmcp_worst = worst_rel_err(&mmcp_res, &mmcp_exp);
98
99    // --- report ---
100    println!("Real-data parity vs R reference estimators (R 4.6.0)\n");
101    println!(
102        "  {:<13} {:<18} {:>7} {:>4} pops {:>3} samples   worst rel err {:>9}",
103        "MCP-counter",
104        "dataset_racle",
105        mcp_genes,
106        mcp_res.populations.len(),
107        mcp_res.samples.len(),
108        format!("{mcp_worst:e}"),
109    );
110    println!(
111        "  {:<13} {:<18} {:>7} {:>4} pops {:>3} samples   worst rel err {:>9}",
112        "mMCP-counter",
113        "dataset_petitprez",
114        mmcp_genes,
115        mmcp_res.populations.len(),
116        mmcp_res.samples.len(),
117        format!("{mmcp_worst:e}"),
118    );
119
120    // --- aggregate metrics (raw matrices are never committed) ---
121    let json = format!(
122        r#"{{
123  "description": "Real-data parity: mcpcounter-rust vs R reference estimators (R 4.6.0)",
124  "regenerate": "Rscript benchmarks/parity_realdata.R && cargo run --example parity_realdata",
125  "threshold_relative_error": {threshold},
126  "datasets": [
127    {{
128      "method": "MCP-counter",
129      "dataset": "dataset_racle",
130      "organism": "human",
131      "citation": "Racle et al. 2017, eLife 6:e26476",
132      "features_type": "HUGO_symbols",
133      "input_genes": {mcp_genes},
134      "populations": {mcp_pops},
135      "samples": {mcp_samples},
136      "worst_relative_error": {mcp_worst}
137    }},
138    {{
139      "method": "mMCP-counter",
140      "dataset": "dataset_petitprez",
141      "organism": "mouse",
142      "citation": "Petitprez et al. 2020, Genome Med 12:86",
143      "features_type": "Gene.Symbol",
144      "genome_version": "GCRm39",
145      "input_genes": {mmcp_genes},
146      "populations": {mmcp_pops},
147      "samples": {mmcp_samples},
148      "worst_relative_error": {mmcp_worst}
149    }}
150  ]
151}}
152"#,
153        threshold = THRESHOLD,
154        mcp_genes = mcp_genes,
155        mcp_pops = mcp_res.populations.len(),
156        mcp_samples = mcp_res.samples.len(),
157        mcp_worst = mcp_worst,
158        mmcp_genes = mmcp_genes,
159        mmcp_pops = mmcp_res.populations.len(),
160        mmcp_samples = mmcp_res.samples.len(),
161        mmcp_worst = mmcp_worst,
162    );
163    if let Err(e) = fs::write(RESULTS_PATH, &json) {
164        eprintln!("warning: could not write {RESULTS_PATH}: {e}");
165    } else {
166        println!("\nwrote {RESULTS_PATH}");
167    }
168
169    // --- gate ---
170    let failed = mcp_worst >= THRESHOLD || mmcp_worst >= THRESHOLD;
171    if failed {
172        eprintln!("\nFAIL: worst relative error exceeds {THRESHOLD:e}");
173        process::exit(1);
174    }
175    println!("\nOK: both methods within {THRESHOLD:e} relative error of R");
176}
Source

pub fn ncol(&self) -> usize

Number of columns (samples).

Source

pub fn row_names(&self) -> &[String]

Row (feature) names.

Examples found in repository?
examples/parity_realdata.rs (line 48)
44fn worst_rel_err(res: &DeconvResult, expected_tsv: &str) -> f64 {
45    let exp = read_tsv_matrix(expected_tsv); // rows = populations, cols = samples
46    assert_eq!(
47        res.populations,
48        exp.row_names(),
49        "population order mismatch"
50    );
51    assert_eq!(res.samples, exp.col_names(), "sample order mismatch");
52
53    let mut worst = 0.0f64;
54    for i in 0..res.populations.len() {
55        for j in 0..res.samples.len() {
56            let got = res.score(i, j);
57            let want = exp.get(i, j);
58            let rel = (got - want).abs() / want.abs().max(1e-300);
59            worst = worst.max(rel);
60        }
61    }
62    worst
63}
Source

pub fn col_names(&self) -> &[String]

Column (sample) names.

Examples found in repository?
examples/parity_realdata.rs (line 51)
44fn worst_rel_err(res: &DeconvResult, expected_tsv: &str) -> f64 {
45    let exp = read_tsv_matrix(expected_tsv); // rows = populations, cols = samples
46    assert_eq!(
47        res.populations,
48        exp.row_names(),
49        "population order mismatch"
50    );
51    assert_eq!(res.samples, exp.col_names(), "sample order mismatch");
52
53    let mut worst = 0.0f64;
54    for i in 0..res.populations.len() {
55        for j in 0..res.samples.len() {
56            let got = res.score(i, j);
57            let want = exp.get(i, j);
58            let rel = (got - want).abs() / want.abs().max(1e-300);
59            worst = worst.max(rel);
60        }
61    }
62    worst
63}
Source

pub fn row_of(&self, name: &str) -> Option<usize>

First row index for a feature name, if present.

Source

pub fn get(&self, row: usize, col: usize) -> f64

Value at (row, col).

Examples found in repository?
examples/parity_realdata.rs (line 57)
44fn worst_rel_err(res: &DeconvResult, expected_tsv: &str) -> f64 {
45    let exp = read_tsv_matrix(expected_tsv); // rows = populations, cols = samples
46    assert_eq!(
47        res.populations,
48        exp.row_names(),
49        "population order mismatch"
50    );
51    assert_eq!(res.samples, exp.col_names(), "sample order mismatch");
52
53    let mut worst = 0.0f64;
54    for i in 0..res.populations.len() {
55        for j in 0..res.samples.len() {
56            let got = res.score(i, j);
57            let want = exp.get(i, j);
58            let rel = (got - want).abs() / want.abs().max(1e-300);
59            worst = worst.max(rel);
60        }
61    }
62    worst
63}

Trait Implementations§

Source§

impl Clone for ExprMatrix

Source§

fn clone(&self) -> ExprMatrix

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ExprMatrix

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.