def get_estimator(model, linear_estimator='ARD', n_channels=3, optimize_hyperparameters=False, **kwargs): if model == 'Linear': from lnpy import linear as linear_models if linear_estimator == 'ARD': estimator = linear_models.ARD(verbose=0) elif linear_estimator == 'Ridge': estimator = linear_models.Ridge(verbose=False) elif model == 'GAM': estimator = GAM(linear_model=linear_estimator, n_channels=n_channels) elif model == 'MLP': estimator = MLP(optimize_hyperparameters=optimize_hyperparameters, alpha=0.0001, hidden_layer_sizes=(100, ), activation='relu', solver='adam', **kwargs) return estimator
def fit(self, X, y, W=None, D=np.zeros((8, 1))): """Fits the model to the data (X, y) Parameters ---------- X : ndarray tensor data of shape (n_samples, N1, ..., NS) y : 1D-array of shape (n_samples, ) labels associated with each sample W : list list of initial covariates (S-entry list; each entry the size of N1, ..., NS) Returns ------- self """ if W == None: # Initialize randomly if W is not provided rng = check_random_state(self.random_state) # Initialise randomly the weights W = [] for i in range(1, T.ndim( X)): # The first dimension of X is the number of samples W.append( T.tensor(rng.randn(X.shape[i], self.weight_rank), **T.context(X))) # Norm of the weight tensor at each iteration norm_W = [] weights = T.ones(self.weight_rank, **T.context(X)) # Need an intercept intercept = 0.0 # functions for fitting spatial gaussians def solve_ald(x, y, cen, sig, rho, delta, nv): tmp_gauss = gaussian(np.arange(0, 27, 0.5), cen, sig, 1) cov_sp = np.zeros((27, 27)) for cc in range(27): np.fill_diagonal(cov_sp[cc:], tmp_gauss[cc:-cc:2]) np.fill_diagonal(cov_sp[:, cc:], tmp_gauss[cc:-cc:2]) np.fill_diagonal(cov_sp, tmp_gauss[::2]) dist_mat = np.zeros((27, 27)) for cc in range(1, 27): np.fill_diagonal(dist_mat[cc:], np.ones((27 - cc, 1)) * (cc**2)) np.fill_diagonal(dist_mat[:, cc:], np.ones((27 - cc, 1)) * (cc**2)) cov_sm = np.exp(-rho - (dist_mat / delta**2)) cov = cov_sm * cov_sp npad = ((0, 1), (0, 1)) cov = np.pad(cov, pad_width=npad, mode='constant', constant_values=0) x = np.concatenate((x, np.ones((x.shape[0], 1))), axis=1) CXX = cov.dot(x.T).dot(x) XY = x.T.dot(y) YY = y.T.dot(y) lamb = np.linalg.solve((1. / nv) * CXX + np.eye(28), cov) lamb_inv = np.linalg.pinv(lamb) mu = np.linalg.solve(CXX + nv * np.eye(28), cov).dot(XY) return mu, lamb, lamb_inv, cov def logevid(pars, x, y): # unpack parameters: extract .value attribute for each parameter parvals = pars.valuesdict() cen = parvals['cen'] sig = parvals['sig'] rho = parvals['rho'] delta = parvals['delta'] nv = parvals['nv'] mu, lamb, lamb_inv, cov = solve_ald(x, y, cen, sig, rho, delta, nv) YY = y.T.dot(y) evid = (-y.size/2)*np.log(2*np.pi*nv) - \ 0.5 * np.log(cov.dot(lamb_inv)) + \ 0.5 * mu.T.dot(lamb_inv).dot(mu) - \ (1/(2*nv)) * YY return -evid def gaussian(x, mu, sig, sc): tmp = np.exp(-np.power(x - mu, 2.) / (2 * np.power(sig, 2.))) return tmp * sc for iteration in trange(self.n_iter_max): # Optimise each factor of W for i in range(len(W)): phi = T.reshape( T.dot(partial_unfold(X, i, skip_begin=1), khatri_rao(W, skip_matrix=i)), (X.shape[0], -1)) # if i == 0: # There should be a better way ridge = ln.SmoothRidge(D=D, verbose=False) ridge.fit(phi, y) W[i] = ridge.coef_[:, None] intercept = ridge.intercept_ elif i == 1: ridge = ln.SmoothRidge(D=(phi.shape[1], 1), second_order=False, verbose=False) ridge.fit(phi, y) W[i] = ridge.coef_[:, None] intercept = ridge.intercept_ elif i < 4: # get initial ridge = ln.Ridge(verbose=False) ridge.fit(phi, y) # set parameters params = lmfit.Parameters() params['cen'] = lmfit.Parameter(value=13, min=7, max=19) params['sig'] = lmfit.Parameter(value=4, min=2, max=9) params['rho'] = lmfit.Parameter(value=-np.log(ridge.alpha), min=-20, max=20) params['delta'] = lmfit.Parameter(value=1., min=-10e6, max=10e6) params['nv'] = lmfit.Parameter(value=ridge.noisevar, min=10e-7, max=10) # solve out = lmfit.minimize(logevid, params, args=(phi, y)) mu, _, _, _ = solve_ald(phi, y, out.params['cen'].value, out.params['sig'].value, out.params['rho'].value, out.params['delta'].value, out.params['nv'].value) W[i] = mu[:-1, None] else: ridge = ln.SmoothRidge(D=(phi.shape[1], 1), zero_order=True, first_order=True, second_order=True, verbose=False) ridge.fit(phi, y) W[i] = ridge.coef_[:, None] intercept = ridge.intercept_ weight_tensor_ = kruskal_to_tensor((weights, W)) norm_W.append(T.norm(weight_tensor_, 2)) # Convergence check if iteration > 1: weight_evolution = abs(norm_W[-1] - norm_W[-2]) / norm_W[-1] if (weight_evolution <= self.tol): if self.verbose: print('\nConverged in {} iterations'.format(iteration)) break self.weight_tensor_ = weight_tensor_ self.kruskal_weight_ = (weights, W) self.intercept_ = intercept self.vec_W_ = kruskal_to_vec((weights, W)) self.n_iterations_ = iteration + 1 self.norm_W_ = norm_W return self
def fit(self, X, y): from lnpy import linear as linear_models n_channels = self.n_channels # estimation a GAM using all dimensions is not working well; # thus we try to estimate the linear weights using a linear model # and then fit a GAM to the linear predictions for each channel from rpy2.robjects.packages import importr from rpy2.robjects import pandas2ri import rpy2.robjects as ro pandas2ri.activate() import pandas as pd try: import pandas.rpy.common as com com_available = True except BaseException: com_available = False mgcv = importr('mgcv') if self.linear_model is None: lin_model = linear_models.ARD(verbose=False) lin_model.fit(X, y) elif isinstance(self.linear_model, string_types): if self.linear_model.upper() == 'ARD': lin_model = linear_models.ARD(verbose=False) elif self.linear_model.upper() == 'RIDGE': lin_model = linear_models.Ridge(verbose=False) lin_model.fit(X, y) N = X.shape[0] w = np.copy(lin_model.get_weights()) m = w.shape[0] / n_channels chan_ind = np.reshape(np.arange(w.shape[0]), (m, n_channels), order='F') Yw_pred = np.zeros((N, n_channels)) for j in range(n_channels): # predictions for channel j Yw_pred[:, j] = np.dot(X[:, chan_ind[:, j]], w[chan_ind[:, j]]) # fit GAM YX = np.hstack((np.atleast_2d(y).T, Yw_pred)) df = pd.DataFrame(YX, columns=self.columns) if com_available: df_r = com.convert_to_r_dataframe(df) else: try: df_r = pandas2ri.py2ri(df) except BaseException: df_r = pandas2ri.pandas2ri(df) mod = self.model_string m = mgcv.gam(ro.r(mod), data=df_r, family='gaussian()', optimizer='perf') self._model = m self._linear_model = lin_model