meanap.pipeline.nmf

Non-negative matrix factorization dimensionality metrics, port of calNMF.m (called from ExtractNetMet.m for the num_nnmf_components /nComponentsRelNS/nnmf_residuals/nnmf_var_explained fields).

Not bit-reproducible against MATLAB, and not even algorithm-identical — unlike the rest of this port, this isn’t just “same algorithm, independent RNG stream”. MATLAB’s built-in nnmf defaults to Alternating Least Squares; this module uses sklearn.decomposition.NMF (coordinate descent), the closest available equivalent in the Python scientific stack. Different NMF solvers can converge to different local optima and even pick a different num_nnmf_components for the same input, since that value depends on where each solver’s reconstruction residual happens to cross the shuffled-data reference residual. The control flow (search for the number of components by comparing residuals against a phase-randomized reference, then sweep every possible rank up to the active-electrode count) is a faithful port; the underlying factorization is not.

Also diverges from calNMF.m in one deliberate way for tractability: MATLAB builds the phase-randomized (“wrap”) spike matrix at the native sampling rate first (spikeTimesToSpikeMatrix at fs, potentially tens of millions of rows for a long recording) and only downsamples afterward (downSampleSum). This module bins spike times directly into the final downsampled time bins — mathematically identical whenever the native matrix’s row count is evenly divisible by the downsampled bin count (the same condition MATLAB’s reshape-based downSampleSum silently requires to not error), while avoiding ever materializing that huge intermediate array.

Functions

cal_nmf(spike_times_list, spike_counts, ...)

Non-negative matrix factorization dimensionality metrics for one recording (lag-independent — call once per recording, not once per lag, matching ExtractNetMet.m's if e == 1 gate).

randomise_spike_train(spike_times, ...)

Circularly "wrap" a spike train around a random cut point, port of randomiseSpikeTrain.m's 'wrap' method.

meanap.pipeline.nmf.cal_nmf(spike_times_list, spike_counts, duration_s, downsample_freq, fs, min_spike_count=1, include_nmf_components=False, rng=None)[source]

Non-negative matrix factorization dimensionality metrics for one recording (lag-independent — call once per recording, not once per lag, matching ExtractNetMet.m’s if e == 1 gate).

Returns a dict with num_nnmf_components, nComponentsRelNS, nnmf_residuals, nnmf_var_explained, randResidualPerComponent — the fields MATLAB unconditionally saves into NetMet — plus, only if include_nmf_components (space-heavy, off by default, matching MATLAB’s Params.includeNMFcomponents), nmfFactors, nmfWeights, downSampleSpikeMatrix, nmfFactorsVarThreshold, nmfWeightsVarThreshold.

Parameters:
  • spike_times_list (list[ndarray])

  • spike_counts (ndarray)

  • duration_s (float)

  • downsample_freq (float)

  • fs (float)

  • min_spike_count (int)

  • include_nmf_components (bool)

  • rng (Generator | None)

Return type:

dict

meanap.pipeline.nmf.randomise_spike_train(spike_times, duration_s, rng)[source]

Circularly “wrap” a spike train around a random cut point, port of randomiseSpikeTrain.m’s 'wrap' method.

Parameters:
  • spike_times (ndarray)

  • duration_s (float)

  • rng (Generator)

Return type:

ndarray