Create equal-width bins for gene expression levels. Divides the expression range into equal-width bins for the Seurat method. This allows modeling of mean-variance relationship by expression level, as highly expressed genes naturally have different variance characteristics. ## Parameters `log_means` - Log-transformed mean expression values `n_bins` - Number of bins to create ## Returns Bin assi
(log_means: &[f64], n_bins: usize)
| 217 | /// 3. Assign each gene to appropriate bin |
| 218 | /// 4. Handle edge cases (NaN values, exact maximum) |
| 219 | fn equal_width_binning(log_means: &[f64], n_bins: usize) -> anyhow::Result<(Vec<usize>, Vec<f64>)> { |
| 220 | // Find min and max (excluding NaN) |
| 221 | let mut valid_means: Vec<f64> = log_means |
| 222 | .iter() |
| 223 | .filter(|x| x.is_finite()) |
| 224 | .copied() |
| 225 | .collect(); |
| 226 | |
| 227 | if valid_means.is_empty() { |
| 228 | return Err(anyhow::anyhow!("No valid mean values found")); |
| 229 | } |
| 230 | |
| 231 | valid_means.sort_by(|a, b| a.partial_cmp(b).unwrap()); |
| 232 | let min_mean = valid_means[0]; |
| 233 | let max_mean = valid_means[valid_means.len() - 1]; |
| 234 | |
| 235 | // Create equal-width bins |
| 236 | let bin_width = (max_mean - min_mean) / n_bins as f64; |
| 237 | let mut bin_edges = vec![0.0; n_bins + 1]; |
| 238 | |
| 239 | for (i, edge) in bin_edges.iter_mut().enumerate().take(n_bins + 1) { |
| 240 | *edge = min_mean + (i as f64) * bin_width; |
| 241 | } |
| 242 | |
| 243 | // Make sure the last edge includes the maximum value |
| 244 | bin_edges[n_bins] = max_mean + 1e-10; |
| 245 | |
| 246 | // Assign each gene to a bin |
| 247 | let mut bin_indices = vec![0; log_means.len()]; |
| 248 | |
| 249 | for (i, &mean) in log_means.iter().enumerate() { |
| 250 | if !mean.is_finite() { |
| 251 | bin_indices[i] = 0; // Assign NaN/inf to first bin |
| 252 | continue; |
| 253 | } |
| 254 | |
| 255 | // Find which bin this value belongs to |
| 256 | let mut bin_idx = 0; |
| 257 | for j in 0..n_bins { |
| 258 | if mean >= bin_edges[j] && mean < bin_edges[j + 1] { |
| 259 | bin_idx = j; |
| 260 | break; |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | // Handle edge case where mean == max_mean |
| 265 | if mean == max_mean { |
| 266 | bin_idx = n_bins - 1; |
| 267 | } |
| 268 | |
| 269 | bin_indices[i] = bin_idx; |
| 270 | } |
| 271 | |
| 272 | Ok((bin_indices, bin_edges)) |
| 273 | } |
| 274 | |
| 275 | /// Calculate mean and standard deviation of dispersions within each expression bin. |
| 276 | /// |
no outgoing calls
no test coverage detected