def test_full_rank(): n, p = 10, 5 X = np.random.randn(n, p) X_, _ = full_rank(X) assert_array_almost_equal(X, X_) X[:, -1] = X[:, :-1].sum(1) X_, cond = full_rank(X) assert cond > 1.e10 assert_array_almost_equal(X, X_)
def test_full_rank(): rng = np.random.RandomState(42) n, p = 10, 5 X = rng.standard_normal(size=(n, p)) X_, _ = full_rank(X) assert_array_almost_equal(X, X_) X[:, -1] = X[:, :-1].sum(1) X_, cond = full_rank(X) assert cond > 1.e10 assert_array_almost_equal(X, X_)
def make_first_level_design_matrix(frame_times, events=None, hrf_model='glover', drift_model='cosine', high_pass=.01, drift_order=1, fir_delays=[0], add_regs=None, add_reg_names=None, min_onset=-24, oversampling=50): """Generate a design matrix from the input parameters Parameters ---------- frame_times : array of shape (n_frames,) The timing of acquisition of the scans in seconds. events : DataFrame instance, optional Events data that describes the experimental paradigm. The DataFrame instance might have these keys: 'onset': column to specify the start time of each events in seconds. An error is raised if this key is missing. 'trial_type': column to specify per-event experimental conditions identifier. If missing each event are labelled 'dummy' and considered to form a unique condition. 'duration': column to specify the duration of each events in seconds. If missing the duration of each events is set to zero. 'modulation': column to specify the amplitude of each events. If missing the default is set to ones(n_events). An experimental paradigm is valid if it has an 'onset' key and a 'duration' key. If these keys are missing an error will be raised. For the others keys a warning will be displayed. Particular attention should be given to the 'trial_type' key which defines the different conditions in the experimental paradigm. hrf_model : {'spm', 'spm + derivative', 'spm + derivative + dispersion', 'glover', 'glover + derivative', 'glover + derivative + dispersion', 'fir', None}, optional, Specifies the hemodynamic response function drift_model : {'polynomial', 'cosine', None}, optional Specifies the desired drift model, high_pass : float, optional High-pass frequency in case of a cosine model (in Hz). drift_order : int, optional Order of the drift model (in case it is polynomial). fir_delays : array of shape(n_onsets) or list, optional, In case of FIR design, yields the array of delays used in the FIR model (in scans). add_regs : array of shape(n_frames, n_add_reg) or pandas DataFrame, optional additional user-supplied regressors, e.g. data driven noise regressors or seed based regressors. add_reg_names : list of (n_add_reg,) strings, optional If None, while add_regs was provided, these will be termed 'reg_%i', i = 0..n_add_reg - 1 If add_regs is a DataFrame, the corresponding column names are used and add_reg_names is ignored. min_onset : float, optional Minimal onset relative to frame_times[0] (in seconds) events that start before frame_times[0] + min_onset are not considered. oversampling: int, optional, Oversampling factor used in temporal convolutions. Returns ------- design_matrix : DataFrame instance, holding the computed design matrix, the index being the frames_times and each column a regressor. """ # check arguments # check that additional regressor specification is correct n_add_regs = 0 if add_regs is not None: if isinstance(add_regs, pd.DataFrame): add_regs_ = add_regs.values add_reg_names = add_regs.columns.tolist() else: add_regs_ = np.atleast_2d(add_regs) n_add_regs = add_regs_.shape[1] assert add_regs_.shape[0] == np.size(frame_times), ValueError( 'Incorrect specification of additional regressors: ' 'length of regressors provided: %d, number of ' 'time-frames: %d' % (add_regs_.shape[0], np.size(frame_times))) # check that additional regressor names are well specified if add_reg_names is None: add_reg_names = ['reg%d' % k for k in range(n_add_regs)] elif len(add_reg_names) != n_add_regs: raise ValueError( 'Incorrect number of additional regressor names was provided' '(%d provided, %d expected' % (len(add_reg_names), n_add_regs)) # computation of the matrix names = [] matrix = None # step 1: events-related regressors if events is not None: # create the condition-related regressors if isinstance(hrf_model, str): hrf_model = hrf_model.lower() matrix, names = _convolve_regressors(events, hrf_model, frame_times, fir_delays, min_onset, oversampling) # step 2: additional regressors if add_regs is not None: # add user-supplied regressors and corresponding names if matrix is not None: matrix = np.hstack((matrix, add_regs)) else: matrix = add_regs names += add_reg_names # step 3: drifts drift, dnames = _make_drift(drift_model, frame_times, drift_order, high_pass) if matrix is not None: matrix = np.hstack((matrix, drift)) else: matrix = drift names += dnames # check column names are all unique if len(np.unique(names)) != len(names): raise ValueError('Design matrix columns do not have unique names') # step 4: Force the design matrix to be full rank at working precision matrix, _ = full_rank(matrix) design_matrix = pd.DataFrame(matrix, columns=names, index=frame_times) return design_matrix