MCPcopy Index your code
hub / github.com/SingleRust/SingleRust / compute_seurat_hvg

Function compute_seurat_hvg

src/memory/processing/hvg/mod.rs:493–572  ·  view source on GitHub ↗

Compute highly variable genes using the Seurat method. The Seurat method models the mean-variance relationship by: 1. Calculating dispersion (variance/mean) for each gene 2. Binning genes by expression level 3. Computing expected dispersion within each bin 4. Normalizing dispersions to z-scores 5. Selecting genes with high normalized dispersion ## Method Details - Uses log1p transformation of me

(
    adata: &IMAnnData,
    x: &IMArrayElement,
    params: HVGParams,
)

Source from the content-addressed store, hash-verified

491/// - `dispersions_norm`: Z-score normalized dispersions
492/// - `highly_variable`: Boolean selection mask
493fn compute_seurat_hvg(
494 adata: &IMAnnData,
495 x: &IMArrayElement,
496 params: HVGParams,
497) -> anyhow::Result<()> {
498 let n_obs = adata.n_obs();
499
500 // Calculate means from raw counts
501 let raw_means: Vec<f64> = x
502 .sum_whole(&Direction::COLUMN)?
503 .iter()
504 .map(|sum: &f64| sum / n_obs as f64)
505 .collect();
506
507 let variances: Vec<f64> = x.variance_whole::<u32, f64>(&Direction::COLUMN)?;
508
509 // Calculate dispersions with proper handling of zero means
510 let dispersions: Vec<f64> = raw_means
511 .iter()
512 .zip(variances.iter())
513 .map(|(&mean, &var)| {
514 let safe_mean = if mean > 1e-12 { mean } else { 1e-12 };
515 var / safe_mean
516 })
517 .collect();
518
519 // For Seurat flavor, use log1p of means for binning and storage
520 // This matches what Python does AFTER reverting log normalization
521 let log1p_means: Vec<f64> = raw_means.iter().map(|&x| (x + 1.0).ln()).collect();
522
523 // Log dispersions with NaN for zero dispersions (matching Python)
524 let log_dispersions: Vec<f64> = dispersions
525 .iter()
526 .map(|&x| {
527 if x > 0.0 {
528 x.ln()
529 } else {
530 f64::NAN // Python sets dispersion[dispersion == 0] = np.nan
531 }
532 })
533 .collect();
534
535 let n_bins = params.n_bins;
536
537 // Use equal-width binning on log1p_means (like Python's pd.cut)
538 let (bin_indices, _) = equal_width_binning(&log1p_means, n_bins)?;
539
540 // Calculate mean and std for each bin
541 let (mut bin_means, mut bin_stds) =
542 calculate_bin_stats(&log_dispersions, &bin_indices, n_bins)?;
543
544 // Handle single-gene bins (like Python's _postprocess_dispersions_seurat)
545 postprocess_seurat_dispersions(&mut bin_means, &mut bin_stds)?;
546
547 // Normalize dispersions
548 let normalized_dispersions =
549 normalize_dispersions(&log_dispersions, &bin_indices, &bin_means, &bin_stds)?;
550

Callers 1

Calls 6

equal_width_binningFunction · 0.85
calculate_bin_statsFunction · 0.85
normalize_dispersionsFunction · 0.85
subset_genesFunction · 0.85
sum_wholeMethod · 0.45

Tested by

no test coverage detected