librosa.decompose.decompose
- librosa.decompose.decompose(S, *, n_components=None, transformer=None, sort=False, fit=True, **kwargs)[source]
Decompose a feature matrix.
Given a spectrogram
S
, produce a decomposition intocomponents
andactivations
such thatS ~= components.dot(activations)
.By default, this is done with with non-negative matrix factorization (NMF), but any
sklearn.decomposition
-type object will work.- Parameters:
- Snp.ndarray [shape=(…, n_features, n_samples), dtype=float]
The input feature matrix (e.g., magnitude spectrogram)
If the input has multiple channels (leading dimensions), they will be automatically flattened prior to decomposition.
If the input is multi-channel, channels and features are automatically flattened into a single axis before the decomposition. For example, a stereo input S with shape (2, n_features, n_samples) is automatically reshaped to (2 * n_features, n_samples).
- n_componentsint > 0 [scalar] or None
number of desired components
if None, then
n_features
components are used- transformerNone or object
If None, use
sklearn.decomposition.NMF
Otherwise, any object with a similar interface to NMF should work.
transformer
must follow the scikit-learn convention, where input data is(n_samples, n_features)
.transformer.fit_transform() will be run on
S.T
(notS
), the return value of which is stored (transposed) asactivations
The components will be retrieved as
transformer.components_.T
:S ~= np.dot(activations, transformer.components_).T
or equivalently:
S ~= np.dot(transformer.components_.T, activations.T)
- sortbool
If
True
, components are sorted by ascending peak frequency.Note
If used with
transformer
, sorting is applied to copies of the decomposition parameters, and not totransformer
internal parameters.Warning
If the input array has more than two dimensions (e.g., if it’s a multi-channel spectrogram), then axis sorting is not supported and a
ParameterError
exception is raised.- fitbool
If True, components are estimated from the input
S
.If False, components are assumed to be pre-computed and stored in
transformer
, and are not changed.- **kwargsAdditional keyword arguments to the default transformer
- Returns:
- components: np.ndarray [shape=(…, n_features, n_components)]
matrix of components (basis elements).
- activations: np.ndarray [shape=(n_components, n_samples)]
transformed matrix/activation matrix
- Raises:
- ParameterError
if
fit
is False and notransformer
object is provided.if the input array is multi-channel and
sort=True
is specified.
See also
sklearn.decomposition
SciKit-Learn matrix decomposition modules
Examples
Decompose a magnitude spectrogram into 16 components with NMF
>>> y, sr = librosa.load(librosa.ex('pistachio'), duration=5) >>> S = np.abs(librosa.stft(y)) >>> comps, acts = librosa.decompose.decompose(S, n_components=16)
Sort components by ascending peak frequency
>>> comps, acts = librosa.decompose.decompose(S, n_components=16, ... sort=True)
Or with sparse dictionary learning
>>> import sklearn.decomposition >>> T = sklearn.decomposition.MiniBatchDictionaryLearning(n_components=16) >>> scomps, sacts = librosa.decompose.decompose(S, transformer=T, sort=True)
>>> import matplotlib.pyplot as plt >>> layout = [list(".AAAA"), list("BCCCC"), list(".DDDD")] >>> fig, ax = plt.subplot_mosaic(layout, constrained_layout=True) >>> librosa.display.specshow(librosa.amplitude_to_db(S, ref=np.max), ... y_axis='log', x_axis='time', ax=ax['A']) >>> ax['A'].set(title='Input spectrogram') >>> ax['A'].label_outer() >>> librosa.display.specshow(librosa.amplitude_to_db(comps, >>> ref=np.max), >>> y_axis='log', ax=ax['B']) >>> ax['B'].set(title='Components') >>> ax['B'].label_outer() >>> ax['B'].sharey(ax['A']) >>> librosa.display.specshow(acts, x_axis='time', ax=ax['C'], cmap='gray_r') >>> ax['C'].set(ylabel='Components', title='Activations') >>> ax['C'].sharex(ax['A']) >>> ax['C'].label_outer() >>> S_approx = comps.dot(acts) >>> img = librosa.display.specshow(librosa.amplitude_to_db(S_approx, >>> ref=np.max), >>> y_axis='log', x_axis='time', ax=ax['D']) >>> ax['D'].set(title='Reconstructed spectrogram') >>> ax['D'].sharex(ax['A']) >>> ax['D'].sharey(ax['A']) >>> ax['D'].label_outer() >>> fig.colorbar(img, ax=list(ax.values()), format="%+2.f dB")