def eof(x, transform=False): ''' Empirical Orthogonal Function (EOF) analysis to finds both time series and spatial patterns. :param x: (*array_like*) Input 2-D array with space-time field. :param transform: (*boolean*) Do space-time transform or not. This transform will speed up the computation if the space location number is much more than time stamps. :returns: (EOF, E, PC) EOF: eigen vector 2-D array; E: eigen values 1-D array; PC: Principle component 2-D array. ''' m, n = x.shape if transform: C = np.dot(x.T, x) E1, EOF1 = np.linalg.eig(C) EOF1 = EOF1[:, ::-1] E = E1[::-1] EOFa = np.dot(x, EOF1) EOF = np.zeros((m, n)) for i in range(n): EOF[:, i] = EOFa[:, i] / np.sqrt(abs(E[i])) PC = np.dot(EOF.T, x) PC = PC[::-1, :] else: C = np.dot(x, x.T) / n E, EOF = np.linalg.eig(C) PC = np.dot(EOF.T, x) EOF = EOF[:, ::-1] PC = PC[::-1, :] E = E[::-1] return EOF, E, PC
def eof(x, svd=False, transform=False): ''' Empirical Orthogonal Function (EOF) analysis to finds both time series and spatial patterns. :param x: (*array_like*) Input 2-D array with space-time field. :param svd: (*boolean*) Using SVD or eigen method. :param transform: (*boolean*) Do space-time transform or not. This transform will speed up the computation if the space location number is much more than time stamps. Only valid when ``svd=False``. :returns: (EOF, E, PC) EOF: eigen vector 2-D array; E: eigen values 1-D array; PC: Principle component 2-D array. ''' has_nan = False if x.contains_nan(): #Has NaN value valid_idx = np.where(x[:, 0] != np.nan)[0] xx = x[valid_idx, :] has_nan = True else: xx = x m, n = xx.shape if svd: U, S, V = np.linalg.svd(xx) EOF = U C = np.zeros((m, n)) for i in range(len(S)): C[i, i] = S[i] PC = np.dot(C, V) E = S**2 / n else: if transform: C = np.dot(xx.T, xx) E1, EOF1 = np.linalg.eig(C) EOF1 = EOF1[:, ::-1] E = E1[::-1] EOFa = np.dot(xx, EOF1) EOF = np.zeros((m, n)) for i in range(n): EOF[:, i] = EOFa[:, i] / np.sqrt(abs(E[i])) PC = np.dot(EOF.T, xx) else: C = np.dot(xx, xx.T) / n E, EOF = np.linalg.eig(C) PC = np.dot(EOF.T, xx) EOF = EOF[:, ::-1] PC = PC[::-1, :] E = E[::-1] if has_nan: _EOF = np.ones(x.shape) * np.nan _PC = np.ones(x.shape) * np.nan _EOF[valid_idx, :] = -EOF _PC[valid_idx, :] = -PC return _EOF, E, _PC else: return EOF, E, PC
def __init__(self, dataset, bw_method=None): self.dataset = np.atleast_2d(dataset) if not np.array(self.dataset).size > 1: raise ValueError("`dataset` input should have multiple elements.") self.dim, self.num_dp = np.array(self.dataset).shape isString = isinstance(bw_method, str) if bw_method is None: pass elif (isString and bw_method == 'scott'): self.covariance_factor = self.scotts_factor elif (isString and bw_method == 'silverman'): self.covariance_factor = self.silverman_factor elif (np.isscalar(bw_method) and not isString): self._bw_method = 'use constant' self.covariance_factor = lambda: bw_method elif callable(bw_method): self._bw_method = bw_method self.covariance_factor = lambda: self._bw_method(self) else: raise ValueError("`bw_method` should be 'scott', 'silverman', a " "scalar or a callable") # Computes the covariance matrix for each Gaussian kernel using # covariance_factor(). self.factor = self.covariance_factor() # Cache covariance and inverse covariance of the data if not hasattr(self, '_data_inv_cov'): self.data_covariance = np.atleast_2d( np.stats.cov(self.dataset, rowvar=1, bias=False)) self.data_inv_cov = np.linalg.inv(self.data_covariance) self.covariance = self.data_covariance * self.factor**2 self.inv_cov = self.data_inv_cov / self.factor**2 self.norm_factor = np.sqrt(np.linalg.det( 2 * np.pi * self.covariance)) * self.num_dp