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 evaluate(self, points): """Evaluate the estimated pdf on a set of points. Parameters ---------- points : (# of dimensions, # of points)-array Alternatively, a (# of dimensions,) vector can be passed in and treated as a single point. Returns ------- values : (# of points,)-array The values at each point. Raises ------ ValueError : if the dimensionality of the input points is different than the dimensionality of the KDE. """ points = np.atleast_2d(points) dim, num_m = np.array(points).shape if dim != self.dim: raise ValueError("points have dimension {}, dataset has dimension " "{}".format(dim, self.dim)) result = np.zeros(num_m) if num_m >= self.num_dp: # there are more points than data, so loop over data for i in range(self.num_dp): diff = self.dataset[:, i, np.newaxis] - points tdiff = np.dot(self.inv_cov, diff) energy = np.sum(diff * tdiff, axis=0) / 2.0 result = result + np.exp(-energy) else: # loop over points for i in range(num_m): diff = self.dataset - points[:, i, np.newaxis] tdiff = np.dot(self.inv_cov, diff) energy = np.sum(diff * tdiff, axis=0) / 2.0 result[i] = np.sum(np.exp(-energy), axis=0) result = result / self.norm_factor return result
def varimax(x, normalize=False, tol=1e-10, it_max=1000): ''' Rotate EOFs according to varimax algorithm :param x: (*array_like*) Input 2-D array. :param normalize: (*boolean*) Determines whether or not to normalize the rows or columns of the loadings before performing the rotation. :param tol: (*float*) Tolerance. :param it_max: (*int*) Specifies the maximum number of iterations to do. :returns: Rotated EOFs and rotate matrix. ''' p, nc = x.shape TT = np.eye(nc) d = 0 for i in range(it_max): z = np.dot(x, TT) B = np.dot( x.T, (z**3 - np.dot(z, np.diag(np.squeeze(np.dot(np.ones((1, p)), (z**2))))) / p)) U, S, Vh = np.linalg.svd(B) TT = np.dot(U, Vh) d2 = d d = np.sum(S) # End if exceeded tolerance. if d < d2 * (1 + tol): break # Final matrix. r = np.dot(x, TT) return r, TT
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