|
14 | 14 | import numpy as np
|
15 | 15 | from scipy import linalg, sparse
|
16 | 16 |
|
| 17 | +from .io.meas_info import _simplify_info |
17 | 18 | from .io.write import start_file, end_file
|
18 | 19 | from .io.proj import (make_projector, _proj_equal, activate_proj,
|
19 |
| - _needs_eeg_average_ref_proj, _check_projs, |
| 20 | + _check_projs, _needs_eeg_average_ref_proj, |
20 | 21 | _has_eeg_average_ref_proj)
|
21 | 22 | from .io import fiff_open
|
22 | 23 | from .io.pick import (pick_types, pick_channels_cov, pick_channels, pick_info,
|
23 | 24 | _picks_by_type, _pick_data_channels,
|
24 | 25 | _DATA_CH_TYPES_SPLIT)
|
25 | 26 |
|
26 | 27 | from .io.constants import FIFF
|
27 |
| -from .io.meas_info import read_bad_channels, _simplify_info, create_info |
| 28 | +from .io.meas_info import read_bad_channels, create_info |
28 | 29 | from .io.proj import _read_proj, _write_proj
|
29 | 30 | from .io.tag import find_tag
|
30 | 31 | from .io.tree import dir_tree_find
|
|
33 | 34 | from .defaults import _handle_default
|
34 | 35 | from .epochs import Epochs
|
35 | 36 | from .event import make_fixed_length_events
|
36 |
| -from .utils import (check_fname, logger, verbose, estimate_rank, |
37 |
| - _compute_row_norms, check_version, _time_mask, warn, |
38 |
| - copy_function_doc_to_method_doc, _pl) |
| 37 | +from .utils import (check_fname, logger, verbose, |
| 38 | + check_version, _time_mask, warn, |
| 39 | + copy_function_doc_to_method_doc, _pl, |
| 40 | + _undo_scaling_cov, _undo_scaling_array, |
| 41 | + _apply_scaling_array) |
39 | 42 | from . import viz
|
| 43 | +from .rank import _estimate_rank_meeg_cov |
40 | 44 |
|
41 | 45 | from .fixes import BaseEstimator, EmpiricalCovariance, _logdet
|
42 | 46 |
|
@@ -629,7 +633,7 @@ def compute_covariance(epochs, keep_sample_mean=True, tmin=None, tmax=None,
|
629 | 633 |
|
630 | 634 | ['shrunk', 'diagonal_fixed', 'empirical', 'factor_analysis']
|
631 | 635 |
|
632 |
| - ``'factor_analysis'`` is removed when `rank` is not 'full'. |
| 636 | + ``'factor_analysis'`` is removed when ``rank`` is not 'full'. |
633 | 637 | The ``'auto'`` mode is not recommended if there are many
|
634 | 638 | segments of data, since computation can take a long time.
|
635 | 639 |
|
@@ -1990,175 +1994,3 @@ def _write_cov(fid, cov):
|
1990 | 1994 |
|
1991 | 1995 | # Done!
|
1992 | 1996 | end_block(fid, FIFF.FIFFB_MNE_COV)
|
1993 |
| - |
1994 |
| - |
1995 |
| -def _apply_scaling_array(data, picks_list, scalings): |
1996 |
| - """Scale data type-dependently for estimation.""" |
1997 |
| - scalings = _check_scaling_inputs(data, picks_list, scalings) |
1998 |
| - if isinstance(scalings, dict): |
1999 |
| - picks_dict = dict(picks_list) |
2000 |
| - scalings = [(picks_dict[k], v) for k, v in scalings.items() |
2001 |
| - if k in picks_dict] |
2002 |
| - for idx, scaling in scalings: |
2003 |
| - data[idx, :] *= scaling # F - order |
2004 |
| - else: |
2005 |
| - data *= scalings[:, np.newaxis] # F - order |
2006 |
| - |
2007 |
| - |
2008 |
| -def _invert_scalings(scalings): |
2009 |
| - if isinstance(scalings, dict): |
2010 |
| - scalings = dict((k, 1. / v) for k, v in scalings.items()) |
2011 |
| - elif isinstance(scalings, np.ndarray): |
2012 |
| - scalings = 1. / scalings |
2013 |
| - return scalings |
2014 |
| - |
2015 |
| - |
2016 |
| -def _undo_scaling_array(data, picks_list, scalings): |
2017 |
| - scalings = _invert_scalings(_check_scaling_inputs(data, picks_list, |
2018 |
| - scalings)) |
2019 |
| - return _apply_scaling_array(data, picks_list, scalings) |
2020 |
| - |
2021 |
| - |
2022 |
| -def _apply_scaling_cov(data, picks_list, scalings): |
2023 |
| - """Scale resulting data after estimation.""" |
2024 |
| - scalings = _check_scaling_inputs(data, picks_list, scalings) |
2025 |
| - scales = None |
2026 |
| - if isinstance(scalings, dict): |
2027 |
| - n_channels = len(data) |
2028 |
| - covinds = list(zip(*picks_list))[1] |
2029 |
| - assert len(data) == sum(len(k) for k in covinds) |
2030 |
| - assert list(sorted(np.concatenate(covinds))) == list(range(len(data))) |
2031 |
| - scales = np.zeros(n_channels) |
2032 |
| - for ch_t, idx in picks_list: |
2033 |
| - scales[idx] = scalings[ch_t] |
2034 |
| - elif isinstance(scalings, np.ndarray): |
2035 |
| - if len(scalings) != len(data): |
2036 |
| - raise ValueError('Scaling factors and data are of incompatible ' |
2037 |
| - 'shape') |
2038 |
| - scales = scalings |
2039 |
| - elif scalings is None: |
2040 |
| - pass |
2041 |
| - else: |
2042 |
| - raise RuntimeError('Arff...') |
2043 |
| - if scales is not None: |
2044 |
| - assert np.sum(scales == 0.) == 0 |
2045 |
| - data *= (scales[None, :] * scales[:, None]) |
2046 |
| - |
2047 |
| - |
2048 |
| -def _undo_scaling_cov(data, picks_list, scalings): |
2049 |
| - scalings = _invert_scalings(_check_scaling_inputs(data, picks_list, |
2050 |
| - scalings)) |
2051 |
| - return _apply_scaling_cov(data, picks_list, scalings) |
2052 |
| - |
2053 |
| - |
2054 |
| -def _check_scaling_inputs(data, picks_list, scalings): |
2055 |
| - """Aux function.""" |
2056 |
| - rescale_dict_ = dict(mag=1e15, grad=1e13, eeg=1e6) |
2057 |
| - |
2058 |
| - scalings_ = None |
2059 |
| - if isinstance(scalings, str) and scalings == 'norm': |
2060 |
| - scalings_ = 1. / _compute_row_norms(data) |
2061 |
| - elif isinstance(scalings, dict): |
2062 |
| - rescale_dict_.update(scalings) |
2063 |
| - scalings_ = rescale_dict_ |
2064 |
| - elif isinstance(scalings, np.ndarray): |
2065 |
| - scalings_ = scalings |
2066 |
| - elif scalings is None: |
2067 |
| - pass |
2068 |
| - else: |
2069 |
| - raise NotImplementedError("No way! That's not a rescaling " |
2070 |
| - 'option: %s' % scalings) |
2071 |
| - return scalings_ |
2072 |
| - |
2073 |
| - |
2074 |
| -def _estimate_rank_meeg_signals(data, info, scalings, tol='auto', |
2075 |
| - return_singular=False): |
2076 |
| - """Estimate rank for M/EEG data. |
2077 |
| -
|
2078 |
| - Parameters |
2079 |
| - ---------- |
2080 |
| - data : np.ndarray of float, shape(n_channels, n_samples) |
2081 |
| - The M/EEG signals. |
2082 |
| - info : Info |
2083 |
| - The measurement info. |
2084 |
| - scalings : dict | 'norm' | np.ndarray | None |
2085 |
| - The rescaling method to be applied. If dict, it will override the |
2086 |
| - following default dict: |
2087 |
| -
|
2088 |
| - dict(mag=1e15, grad=1e13, eeg=1e6) |
2089 |
| -
|
2090 |
| - If 'norm' data will be scaled by channel-wise norms. If array, |
2091 |
| - pre-specified norms will be used. If None, no scaling will be applied. |
2092 |
| - tol : float | str |
2093 |
| - Tolerance. See ``estimate_rank``. |
2094 |
| - return_singular : bool |
2095 |
| - If True, also return the singular values that were used |
2096 |
| - to determine the rank. |
2097 |
| -
|
2098 |
| - Returns |
2099 |
| - ------- |
2100 |
| - rank : int |
2101 |
| - Estimated rank of the data. |
2102 |
| - s : array |
2103 |
| - If return_singular is True, the singular values that were |
2104 |
| - thresholded to determine the rank are also returned. |
2105 |
| - """ |
2106 |
| - picks_list = _picks_by_type(info) |
2107 |
| - _apply_scaling_array(data, picks_list, scalings) |
2108 |
| - if data.shape[1] < data.shape[0]: |
2109 |
| - ValueError("You've got fewer samples than channels, your " |
2110 |
| - "rank estimate might be inaccurate.") |
2111 |
| - out = estimate_rank(data, tol=tol, norm=False, |
2112 |
| - return_singular=return_singular) |
2113 |
| - rank = out[0] if isinstance(out, tuple) else out |
2114 |
| - ch_type = ' + '.join(list(zip(*picks_list))[0]) |
2115 |
| - logger.info('estimated rank (%s): %d' % (ch_type, rank)) |
2116 |
| - _undo_scaling_array(data, picks_list, scalings) |
2117 |
| - return out |
2118 |
| - |
2119 |
| - |
2120 |
| -def _estimate_rank_meeg_cov(data, info, scalings, tol='auto', |
2121 |
| - return_singular=False): |
2122 |
| - """Estimate rank of M/EEG covariance data, given the covariance. |
2123 |
| -
|
2124 |
| - Parameters |
2125 |
| - ---------- |
2126 |
| - data : np.ndarray of float, shape (n_channels, n_channels) |
2127 |
| - The M/EEG covariance. |
2128 |
| - info : Info |
2129 |
| - The measurement info. |
2130 |
| - scalings : dict | 'norm' | np.ndarray | None |
2131 |
| - The rescaling method to be applied. If dict, it will override the |
2132 |
| - following default dict: |
2133 |
| -
|
2134 |
| - dict(mag=1e12, grad=1e11, eeg=1e5) |
2135 |
| -
|
2136 |
| - If 'norm' data will be scaled by channel-wise norms. If array, |
2137 |
| - pre-specified norms will be used. If None, no scaling will be applied. |
2138 |
| - tol : float | str |
2139 |
| - Tolerance. See ``estimate_rank``. |
2140 |
| - return_singular : bool |
2141 |
| - If True, also return the singular values that were used |
2142 |
| - to determine the rank. |
2143 |
| -
|
2144 |
| - Returns |
2145 |
| - ------- |
2146 |
| - rank : int |
2147 |
| - Estimated rank of the data. |
2148 |
| - s : array |
2149 |
| - If return_singular is True, the singular values that were |
2150 |
| - thresholded to determine the rank are also returned. |
2151 |
| - """ |
2152 |
| - picks_list = _picks_by_type(info) |
2153 |
| - scalings = _handle_default('scalings_cov_rank', scalings) |
2154 |
| - _apply_scaling_cov(data, picks_list, scalings) |
2155 |
| - if data.shape[1] < data.shape[0]: |
2156 |
| - ValueError("You've got fewer samples than channels, your " |
2157 |
| - "rank estimate might be inaccurate.") |
2158 |
| - out = estimate_rank(data, tol=tol, norm=False, |
2159 |
| - return_singular=return_singular) |
2160 |
| - rank = out[0] if isinstance(out, tuple) else out |
2161 |
| - ch_type = ' + '.join(list(zip(*picks_list))[0]) |
2162 |
| - logger.info('estimated rank (%s): %d' % (ch_type, rank)) |
2163 |
| - _undo_scaling_cov(data, picks_list, scalings) |
2164 |
| - return out |
0 commit comments