def solve(a, b, overwrite_a=False, overwrite_b=False): """ Solve a linear system ``a x = b`` Parameters ---------- a : (N, N) array_like left-hand-side matrix b : (N, NRHS) array_like right-hand-side matrix overwrite_a : bool, optional whether we are allowed to overwrite the matrix `a` overwrite_b : bool, optional whether we are allowed to overwrite the matrix `b` Returns ------- x : (N, NRHS) ndarray solution matrix """ a1 = atleast_2d(_asarray_validated(a, check_finite=False)) b1 = atleast_1d(_asarray_validated(b, check_finite=False)) n = a1.shape[0] overwrite_a = overwrite_a or _datacopied(a1, a) overwrite_b = overwrite_b or _datacopied(b1, b) if a1.shape[0] != a1.shape[1]: raise ValueError('LHS needs to be a square matrix.') if n != b1.shape[0]: # Last chance to catch 1x1 scalar a and 1D b arrays if not (n == 1 and b1.size != 0): raise ValueError('Input b has to have same number of rows as ' 'input a') # regularize 1D b arrays to 2D if b1.ndim == 1: if n == 1: b1 = b1[None, :] else: b1 = b1[:, None] b_is_1D = True else: b_is_1D = False gesv = get_lapack_funcs('gesv', (a1, b1)) _, _, x, info = gesv(a1, b1, overwrite_a=overwrite_a, overwrite_b=overwrite_b) if info > 0: raise LinAlgError("Singular matrix") if info < 0: raise ValueError('illegal value in %d-th argument of internal ' 'gesv' % -info) if b_is_1D: return x.ravel() return x
def py_vq2(obs, code_book, check_finite=True): """2nd Python version of vq algorithm. The algorithm simply computes the euclidian distance between each observation and every frame in the code_book/ Parameters ---------- obs : ndarray Expect a rank 2 array. Each row is one observation. code_book : ndarray Code book to use. Same format than obs. Should have same number of features (eg columns) than obs. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- code : ndarray code[i] gives the label of the ith obversation, that its code is code_book[code[i]]. mind_dist : ndarray min_dist[i] gives the distance between the ith observation and its corresponding code. Notes ----- This could be faster when number of codebooks is small, but it becomes a real memory hog when codebook is large. It requires N by M by O storage where N=number of obs, M = number of features, and O = number of codes. """ obs = _asarray_validated(obs, check_finite=check_finite) code_book = _asarray_validated(code_book, check_finite=check_finite) d = shape(obs)[1] # code books and observations should have same number of features if not d == code_book.shape[1]: raise ValueError( """ code book(%d) and obs(%d) should have the same number of features (eg columns)""" % (code_book.shape[1], d) ) diff = obs[newaxis, :, :] - code_book[:, newaxis, :] dist = sqrt(np.sum(diff * diff, -1)) code = argmin(dist, 0) min_dist = minimum.reduce(dist, 0) # The next line I think is equivalent and should be faster than the one # above, but in practice didn't seem to make much difference: # min_dist = choose(code,dist) return code, min_dist
def py_vq2(obs, code_book, check_finite=True): """2nd Python version of vq algorithm. The algorithm simply computes the euclidian distance between each observation and every frame in the code_book/ Parameters ---------- obs : ndarray Expect a rank 2 array. Each row is one observation. code_book : ndarray Code book to use. Same format than obs. Should have same number of features (eg columns) than obs. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- code : ndarray code[i] gives the label of the ith obversation, that its code is code_book[code[i]]. mind_dist : ndarray min_dist[i] gives the distance between the ith observation and its corresponding code. Notes ----- This could be faster when number of codebooks is small, but it becomes a real memory hog when codebook is large. It requires N by M by O storage where N=number of obs, M = number of features, and O = number of codes. """ obs = _asarray_validated(obs, check_finite=check_finite) code_book = _asarray_validated(code_book, check_finite=check_finite) d = shape(obs)[1] # code books and observations should have same number of features if not d == code_book.shape[1]: raise ValueError(""" code book(%d) and obs(%d) should have the same number of features (eg columns)""" % (code_book.shape[1], d)) diff = obs[newaxis, :, :] - code_book[:, newaxis, :] dist = sqrt(np.sum(diff * diff, -1)) code = argmin(dist, 0) min_dist = minimum.reduce(dist, 0) # The next line I think is equivalent and should be faster than the one # above, but in practice didn't seem to make much difference: # min_dist = choose(code,dist) return code, min_dist
def py_vq(obs, code_book, check_finite=True): """ Python version of vq algorithm. The algorithm computes the Euclidean distance between each observation and every frame in the code_book. Parameters ---------- obs : ndarray Expects a rank 2 array. Each row is one observation. code_book : ndarray Code book to use. Same format than obs. Should have same number of features (e.g., columns) than obs. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- code : ndarray code[i] gives the label of the ith obversation; its code is code_book[code[i]]. mind_dist : ndarray min_dist[i] gives the distance between the ith observation and its corresponding code. Notes ----- This function is slower than the C version but works for all input types. If the inputs have the wrong types for the C versions of the function, this one is called as a last resort. It is about 20 times slower than the C version. """ obs = _asarray_validated(obs, check_finite=check_finite) code_book = _asarray_validated(code_book, check_finite=check_finite) if obs.ndim != code_book.ndim: raise ValueError("Observation and code_book should have the same rank") if obs.ndim == 1: obs = obs[:, np.newaxis] code_book = code_book[:, np.newaxis] dist = cdist(obs, code_book) code = dist.argmin(axis=1) min_dist = dist[np.arange(len(code)), code] return code, min_dist
def py_vq(obs, code_book, check_finite=True): """ Python version of vq algorithm. The algorithm computes the euclidian distance between each observation and every frame in the code_book. Parameters ---------- obs : ndarray Expects a rank 2 array. Each row is one observation. code_book : ndarray Code book to use. Same format than obs. Should have same number of features (eg columns) than obs. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- code : ndarray code[i] gives the label of the ith obversation, that its code is code_book[code[i]]. mind_dist : ndarray min_dist[i] gives the distance between the ith observation and its corresponding code. Notes ----- This function is slower than the C version but works for all input types. If the inputs have the wrong types for the C versions of the function, this one is called as a last resort. It is about 20 times slower than the C version. """ obs = _asarray_validated(obs, check_finite=check_finite) code_book = _asarray_validated(code_book, check_finite=check_finite) if obs.ndim != code_book.ndim: raise ValueError("Observation and code_book should have the same rank") if obs.ndim == 1: obs = obs[:, np.newaxis] code_book = code_book[:, np.newaxis] dist = cdist(obs, code_book) code = dist.argmin(axis=1) min_dist = dist[np.arange(len(code)), code] return code, min_dist
def __init__(self, x, y, axis=0, extrapolate=None): x = _asarray_validated(x, check_finite=False, as_inexact=True) y = _asarray_validated(y, check_finite=False, as_inexact=True) axis = axis % y.ndim xp = x.reshape((x.shape[0],) + (1,) * (y.ndim - 1)) yp = np.rollaxis(y, axis) dk = self._find_derivatives(xp, yp) data = np.hstack((yp[:, None, ...], dk[:, None, ...])) _b = BPoly.from_derivatives(x, data, orders=None) super(PchipInterpolator_new, self).__init__(_b.c, _b.x, extrapolate=extrapolate) self.axis = axis
def auxFixedPoint(function, x0, maxit, tol, args=()): """ Encontrar el punto fijo de un vector columna nx1. Dada una función de una o más varaiables y un punto de inicio, encontrar el punto fijo de la función. Dondé ``func(x0) == x0``. Parametros ---------- func : function Función a evaluar. x0 : vector Punto fijo de la función- args : tuple Argumentos para la función. tol : float Tolerancia de convergencia, recomendado: 1e-08. maxit : int Maximo de iteraciones. References ---------- .. [1] Burden, Faires, "Numerical Analysis", 5th edition, pg. 80 -------- """ x0 = _asarray_validated(x0, as_inexact=True) #Verifica si el input es valido return fixedPoint(function, x0, args, tol, maxit)
def fixed_point(func, x0, args=(), xtol=1e-8, maxiter=500, method='iteration'): """ Find a fixed point of the function. Given a function of one or more variables and a starting point, find a fixed-point of the function: i.e. where ``func(x0) == x0``. Parameters ---------- func : function Function to evaluate. x0 : array_like Fixed point of function. args : tuple, optional Extra arguments to `func`. xtol : float, optional Convergence tolerance, defaults to 1e-08. maxiter : int, optional Maximum number of iterations, defaults to 500. method : {"del2", "iteration"}, optional Method of finding the fixed-point, defaults to "del2" which uses Steffensen's Method with Aitken's ``Del^2`` convergence acceleration [1]_. The "iteration" method simply iterates the function until convergence is detected, without attempting to accelerate the convergence. References ---------- .. [1] Burden, Faires, "Numerical Analysis", 5th edition, pg. 80 Examples -------- """ use_accel = {'del2': True, 'iteration': True}[method] x0 = _asarray_validated(x0, as_inexact=True) return _fixed_point_helper(func, x0, args, xtol, maxiter, use_accel)
def __init__(self, x, y, axis=0, extrapolate=None): x = _asarray_validated(x, check_finite=False, as_inexact=True) y = _asarray_validated(y, check_finite=False, as_inexact=True) axis = axis % y.ndim xp = x.reshape((x.shape[0],) + (1,)*(y.ndim-1)) yp = np.rollaxis(y, axis) dk = self._find_derivatives(xp, yp) data = np.hstack((yp[:, None, ...], dk[:, None, ...])) _b = BPoly.from_derivatives(x, data, orders=None) super(PchipInterpolator, self).__init__(_b.c, _b.x, extrapolate=extrapolate) self.axis = axis
def whiten(obs, check_finite=True): """ Normalize a group of observations on a per feature basis. Before running k-means, it is beneficial to rescale each feature dimension of the observation set by its standard deviation (i.e. "whiten" it - as in "white noise" where each frequency has equal power). Each feature is divided by its standard deviation across all observations to give it unit variance. Parameters ---------- obs : ndarray Each row of the array is an observation. The columns are the features seen during each observation. >>> # f0 f1 f2 >>> obs = [[ 1., 1., 1.], #o0 ... [ 2., 2., 2.], #o1 ... [ 3., 3., 3.], #o2 ... [ 4., 4., 4.]] #o3 check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- result : ndarray Contains the values in `obs` scaled by the standard deviation of each column. Examples -------- >>> import numpy as np >>> from scipy.cluster.vq import whiten >>> features = np.array([[1.9, 2.3, 1.7], ... [1.5, 2.5, 2.2], ... [0.8, 0.6, 1.7,]]) >>> whiten(features) array([[ 4.17944278, 2.69811351, 7.21248917], [ 3.29956009, 2.93273208, 9.33380951], [ 1.75976538, 0.7038557 , 7.21248917]]) """ obs = _asarray_validated(obs, check_finite=check_finite) std_dev = obs.std(axis=0) zero_std_mask = std_dev == 0 if zero_std_mask.any(): std_dev[zero_std_mask] = 1.0 warnings.warn( "Some columns have standard deviation zero. " "The values of these columns will not change.", RuntimeWarning) return obs / std_dev
def whiten(obs, check_finite=True): """ Normalize a group of observations on a per feature basis. Before running k-means, it is beneficial to rescale each feature dimension of the observation set with whitening. Each feature is divided by its standard deviation across all observations to give it unit variance. Parameters ---------- obs : ndarray Each row of the array is an observation. The columns are the features seen during each observation. >>> # f0 f1 f2 >>> obs = [[ 1., 1., 1.], #o0 ... [ 2., 2., 2.], #o1 ... [ 3., 3., 3.], #o2 ... [ 4., 4., 4.]] #o3 check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- result : ndarray Contains the values in `obs` scaled by the standard deviation of each column. Examples -------- >>> from scipy.cluster.vq import whiten >>> features = np.array([[1.9, 2.3, 1.7], ... [1.5, 2.5, 2.2], ... [0.8, 0.6, 1.7,]]) >>> whiten(features) array([[ 4.17944278, 2.69811351, 7.21248917], [ 3.29956009, 2.93273208, 9.33380951], [ 1.75976538, 0.7038557 , 7.21248917]]) """ obs = _asarray_validated(obs, check_finite=check_finite) std_dev = std(obs, axis=0) zero_std_mask = std_dev == 0 if zero_std_mask.any(): std_dev[zero_std_mask] = 1.0 warnings.warn("Some columns have standard deviation zero. " "The values of these columns will not change.", RuntimeWarning) return obs / std_dev
def whiten(obs, check_finite=True, std_dev=None): obs = _asarray_validated(obs, check_finite=check_finite) if std_dev is None: std_dev = np.std(obs, axis=0) zero_std_mask = std_dev == 0 if zero_std_mask.any(): std_dev[zero_std_mask] = 1.0 warnings.warn( "Some columns have standard deviation zero. " "The values of these columns will not change.", RuntimeWarning) return (std_dev, obs / std_dev)
def whiten(obs, check_finite=False): """Adapted from c:/python27/lib/site- packages/skimage/filters/thresholding.py to return array and std_dev.""" obs = _asarray_validated(obs, check_finite=check_finite) std_dev = np.std(obs, axis=0) zero_std_mask = std_dev == 0 if zero_std_mask.any(): std_dev[zero_std_mask] = 1.0 raise RuntimeWarning( 'Some columns have standard deviation zero. The values of these columns will not change.' ) return obs / std_dev, std_dev
def fixed_point(func, x0, args=(), xtol=1e-8, maxiter=500, method='del2'): """ Find a fixed point of the function. Given a function of one or more variables and a starting point, find a fixed-point of the function: i.e. where ``func(x0) == x0``. Parameters ---------- func : function Function to evaluate. x0 : array_like Fixed point of function. args : tuple, optional Extra arguments to `func`. xtol : float, optional Convergence tolerance, defaults to 1e-08. maxiter : int, optional Maximum number of iterations, defaults to 500. method : {"del2", "iteration"}, optional Method of finding the fixed-point, defaults to "del2" which uses Steffensen's Method with Aitken's ``Del^2`` convergence acceleration [1]_. The "iteration" method simply iterates the function until convergence is detected, without attempting to accelerate the convergence. References ---------- .. [1] Burden, Faires, "Numerical Analysis", 5th edition, pg. 80 Examples -------- >>> from scipy import optimize >>> def func(x, c1, c2): ... return np.sqrt(c1/(x+c2)) >>> c1 = np.array([10,12.]) >>> c2 = np.array([3, 5.]) >>> optimize.fixed_point(func, [1.2, 1.3], args=(c1,c2)) array([ 1.4920333 , 1.37228132]) """ use_accel = {'del2': True, 'iteration': False}[method] x0 = _asarray_validated(x0, as_inexact=True) return _fixed_point_helper(func, x0, args, xtol, maxiter, use_accel)
def eigh(a, overwrite_a=False, check_finite=True): """Efficient wrapper for eigh. Parameters ---------- a : ndarray, shape (n_components, n_components) The symmetric array operate on. overwrite_a : bool If True, the contents of a can be overwritten for efficiency. check_finite : bool If True, check that all elements are finite. Returns ------- w : ndarray, shape (n_components,) The N eigenvalues, in ascending order, each repeated according to its multiplicity. v : ndarray, shape (n_components, n_components) The normalized eigenvector corresponding to the eigenvalue ``w[i]`` is the column ``v[:, i]``. """ # We use SYEVD, see https://github.com/scipy/scipy/issues/9212 if check_finite: a = _asarray_validated(a, check_finite=check_finite) if a.dtype == np.float64: evr, driver = dsyevd, 'syevd' else: assert a.dtype == np.complex128 evr, driver = zheevd, 'heevd' w, v, info = evr(a, lower=1, overwrite_a=overwrite_a) if info == 0: return w, v if info < 0: raise ValueError('illegal value in argument %d of internal %s' % (-info, driver)) else: raise LinAlgError("internal fortran routine failed to converge: " "%i off-diagonal elements of an " "intermediate tridiagonal form did not converge" " to zero." % info)
def logsumexp(a, axis=None, b=None, keepdims=False, return_sign=False): a = _asarray_validated(a, check_finite=False) if b is not None: a, b = np.broadcast_arrays(a, b) if np.any(b == 0): a = a + 0. # promote to at least float a[b == 0] = -np.inf a_max = np.amax(a, axis=axis, keepdims=True) if a_max.ndim > 0: a_max[~np.isfinite(a_max)] = 0 elif not np.isfinite(a_max): a_max = 0 if b is not None: b = np.asarray(b) tmp = b * np.exp(a - a_max) else: tmp = np.exp(a - a_max) # suppress warnings about log of zero with np.errstate(divide='ignore'): s = np.sum(tmp, axis=axis, keepdims=keepdims) if return_sign: sgn = np.sign(s) s *= sgn # /= makes more sense but we need zero -> zero out = np.log(s) if not keepdims: a_max = np.squeeze(a_max, axis=axis) out += a_max if return_sign: return out, sgn else: return out
def inv(a, overwrite_a=False): """ Inverts a matrix Parameters ---------- a : (N, N) array_like the matrix to be inverted. overwrite_a : bool, optional whether we are allowed to overwrite the matrix `a` Returns ------- x : (N, N) ndarray The inverted matrix """ a1 = atleast_2d(_asarray_validated(a, check_finite=False)) overwrite_a = overwrite_a or _datacopied(a1, a) if a1.shape[0] != a1.shape[1]: raise ValueError('Input a needs to be a square matrix.') getrf, getri, getri_lwork = get_lapack_funcs( ('getrf', 'getri', 'getri_lwork'), (a1, )) lu, piv, info = getrf(a1, overwrite_a=overwrite_a) if info == 0: lwork = _compute_lwork(getri_lwork, a1.shape[0]) lwork = int(1.01 * lwork) x, info = getri(lu, piv, lwork=lwork, overwrite_lu=True) if info > 0: raise LinAlgError("Singular matrix") if info < 0: raise ValueError('illegal value in %d-th argument of internal ' 'getrf|getri' % -info) return x
def py_vq(obs, code_book, check_finite=True): """ Python version of vq algorithm. The algorithm computes the euclidian distance between each observation and every frame in the code_book. Parameters ---------- obs : ndarray Expects a rank 2 array. Each row is one observation. code_book : ndarray Code book to use. Same format than obs. Should have same number of features (eg columns) than obs. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- code : ndarray code[i] gives the label of the ith obversation, that its code is code_book[code[i]]. mind_dist : ndarray min_dist[i] gives the distance between the ith observation and its corresponding code. Notes ----- This function is slower than the C version but works for all input types. If the inputs have the wrong types for the C versions of the function, this one is called as a last resort. It is about 20 times slower than the C version. """ obs = _asarray_validated(obs, check_finite=check_finite) code_book = _asarray_validated(code_book, check_finite=check_finite) # n = number of observations # d = number of features if np.ndim(obs) == 1: if not np.ndim(obs) == np.ndim(code_book): raise ValueError( "Observation and code_book should have the same rank") else: return _py_vq_1d(obs, code_book) else: (n, d) = shape(obs) # code books and observations should have same number of features and same # shape if not np.ndim(obs) == np.ndim(code_book): raise ValueError("Observation and code_book should have the same rank") elif not d == code_book.shape[1]: raise ValueError("Code book(%d) and obs(%d) should have the same " "number of features (eg columns)""" % (code_book.shape[1], d)) code = zeros(n, dtype=int) min_dist = zeros(n) for i in range(n): dist = np.sum((obs[i] - code_book) ** 2, 1) code[i] = argmin(dist) min_dist[i] = dist[code[i]] return code, sqrt(min_dist)
def sqrtm(A, disp=True, blocksize=64): """ Matrix square root. Parameters ---------- A : (N, N) array_like Matrix whose square root to evaluate disp : bool, optional Print warning if error in the result is estimated large instead of returning estimated error. (Default: True) blocksize : integer, optional If the blocksize is not degenerate with respect to the size of the input array, then use a blocked algorithm. (Default: 64) Returns ------- sqrtm : (N, N) ndarray Value of the sqrt function at `A` errest : float (if disp == False) Frobenius norm of the estimated error, ||err||_F / ||A||_F References ---------- .. [1] Edvin Deadman, Nicholas J. Higham, Rui Ralha (2013) "Blocked Schur Algorithms for Computing the Matrix Square Root, Lecture Notes in Computer Science, 7782. pp. 171-182. Examples -------- >>> from scipy.linalg import sqrtm >>> a = np.array([[1.0, 3.0], [1.0, 4.0]]) >>> r = sqrtm(a) >>> r array([[ 0.75592895, 1.13389342], [ 0.37796447, 1.88982237]]) >>> r.dot(r) array([[ 1., 3.], [ 1., 4.]]) """ A = _asarray_validated(A, check_finite=True, as_inexact=True) if len(A.shape) != 2: raise ValueError("Non-matrix input to matrix function.") if blocksize < 1: raise ValueError("The blocksize should be at least 1.") keep_it_real = np.isrealobj(A) if keep_it_real: T, Z = schur(A) if not np.array_equal(T, np.triu(T)): T, Z = rsf2csf(T, Z) else: T, Z = schur(A, output='complex') failflag = False try: R = _sqrtm_triu(T, blocksize=blocksize) ZH = np.conjugate(Z).T X = Z.dot(R).dot(ZH) except SqrtmError: failflag = True X = np.empty_like(A) X.fill(np.nan) if disp: nzeig = np.any(np.diag(T) == 0) if nzeig: print("Matrix is singular and may not have a square root.") elif failflag: print("Failed to find a square root.") return X else: try: arg2 = norm(X.dot(X) - A, 'fro')**2 / norm(A, 'fro') except ValueError: # NaNs in matrix arg2 = np.inf return X, arg2
def vq(obs, code_book, check_finite=True): """ Assign codes from a code book to observations. Assigns a code from a code book to each observation. Each observation vector in the 'M' by 'N' `obs` array is compared with the centroids in the code book and assigned the code of the closest centroid. The features in `obs` should have unit variance, which can be achieved by passing them through the whiten function. The code book can be created with the k-means algorithm or a different encoding algorithm. Parameters ---------- obs : ndarray Each row of the 'M' x 'N' array is an observation. The columns are the "features" seen during each observation. The features must be whitened first using the whiten function or something equivalent. code_book : ndarray The code book is usually generated using the k-means algorithm. Each row of the array holds a different code, and the columns are the features of the code. >>> # f0 f1 f2 f3 >>> code_book = [ ... [ 1., 2., 3., 4.], #c0 ... [ 1., 2., 3., 4.], #c1 ... [ 1., 2., 3., 4.]] #c2 check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- code : ndarray A length M array holding the code book index for each observation. dist : ndarray The distortion (distance) between the observation and its nearest code. Examples -------- >>> from numpy import array >>> from scipy.cluster.vq import vq >>> code_book = array([[1.,1.,1.], ... [2.,2.,2.]]) >>> features = array([[ 1.9,2.3,1.7], ... [ 1.5,2.5,2.2], ... [ 0.8,0.6,1.7]]) >>> vq(features,code_book) (array([1, 1, 0],'i'), array([ 0.43588989, 0.73484692, 0.83066239])) """ obs = _asarray_validated(obs, check_finite=check_finite) code_book = _asarray_validated(code_book, check_finite=check_finite) ct = common_type(obs, code_book) c_obs = obs.astype(ct, copy=False) if code_book.dtype != ct: c_code_book = code_book.astype(ct) else: c_code_book = code_book if ct in (single, double): results = _vq.vq(c_obs, c_code_book) else: results = py_vq(obs, code_book) return results
def kmeans2(data, k, iter=10, thresh=1e-5, minit='random', missing='warn', check_finite=True): """ Classify a set of observations into k clusters using the k-means algorithm. The algorithm attempts to minimize the Euclidean distance between observations and centroids. Several initialization methods are included. Parameters ---------- data : ndarray A 'M' by 'N' array of 'M' observations in 'N' dimensions or a length 'M' array of 'M' 1-D observations. k : int or ndarray The number of clusters to form as well as the number of centroids to generate. If `minit` initialization string is 'matrix', or if a ndarray is given instead, it is interpreted as initial cluster to use instead. iter : int, optional Number of iterations of the k-means algorithm to run. Note that this differs in meaning from the iters parameter to the kmeans function. thresh : float, optional (not used yet) minit : str, optional Method for initialization. Available methods are 'random', 'points', '++' and 'matrix': 'random': generate k centroids from a Gaussian with mean and variance estimated from the data. 'points': choose k observations (rows) at random from data for the initial centroids. '++': choose k observations accordingly to the kmeans++ method (careful seeding) 'matrix': interpret the k parameter as a k by M (or length k array for 1-D data) array of initial centroids. missing : str, optional Method to deal with empty clusters. Available methods are 'warn' and 'raise': 'warn': give a warning and continue. 'raise': raise an ClusterError and terminate the algorithm. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- centroid : ndarray A 'k' by 'N' array of centroids found at the last iteration of k-means. label : ndarray label[i] is the code or index of the centroid the ith observation is closest to. See Also -------- kmeans References ---------- .. [1] D. Arthur and S. Vassilvitskii, "k-means++: the advantages of careful seeding", Proceedings of the Eighteenth Annual ACM-SIAM Symposium on Discrete Algorithms, 2007. Examples -------- >>> from scipy.cluster.vq import kmeans2 >>> import matplotlib.pyplot as plt Create z, an array with shape (100, 2) containing a mixture of samples from three multivariate normal distributions. >>> np.random.seed(12345678) >>> a = np.random.multivariate_normal([0, 6], [[2, 1], [1, 1.5]], size=45) >>> b = np.random.multivariate_normal([2, 0], [[1, -1], [-1, 3]], size=30) >>> c = np.random.multivariate_normal([6, 4], [[5, 0], [0, 1.2]], size=25) >>> z = np.concatenate((a, b, c)) >>> np.random.shuffle(z) Compute three clusters. >>> centroid, label = kmeans2(z, 3, minit='points') >>> centroid array([[-0.35770296, 5.31342524], [ 2.32210289, -0.50551972], [ 6.17653859, 4.16719247]]) How many points are in each cluster? >>> counts = np.bincount(label) >>> counts array([52, 27, 21]) Plot the clusters. >>> w0 = z[label == 0] >>> w1 = z[label == 1] >>> w2 = z[label == 2] >>> plt.plot(w0[:, 0], w0[:, 1], 'o', alpha=0.5, label='cluster 0') >>> plt.plot(w1[:, 0], w1[:, 1], 'd', alpha=0.5, label='cluster 1') >>> plt.plot(w2[:, 0], w2[:, 1], 's', alpha=0.5, label='cluster 2') >>> plt.plot(centroid[:, 0], centroid[:, 1], 'k*', label='centroids') >>> plt.axis('equal') >>> plt.legend(shadow=True) >>> plt.show() """ if int(iter) < 1: raise ValueError("Invalid iter (%s), " "must be a positive integer." % iter) try: miss_meth = _valid_miss_meth[missing] except KeyError: raise ValueError("Unknown missing method %r" % (missing, )) data = _asarray_validated(data, check_finite=check_finite) if data.ndim == 1: d = 1 elif data.ndim == 2: d = data.shape[1] else: raise ValueError("Input of rank > 2 is not supported.") if data.size < 1: raise ValueError("Empty input is not supported.") # If k is not a single value, it should be compatible with data's shape if minit == 'matrix' or not np.isscalar(k): code_book = np.array(k, copy=True) if data.ndim != code_book.ndim: raise ValueError("k array doesn't match data rank") nc = len(code_book) if data.ndim > 1 and code_book.shape[1] != d: raise ValueError("k array doesn't match data dimension") else: nc = int(k) if nc < 1: raise ValueError("Cannot ask kmeans2 for %d clusters" " (k was %s)" % (nc, k)) elif nc != k: warnings.warn("k was not an integer, was converted.") try: init_meth = _valid_init_meth[minit] except KeyError: raise ValueError("Unknown init method %r" % (minit, )) else: code_book = init_meth(data, k) for i in range(iter): # Compute the nearest neighbor for each obs using the current code book label = vq(data, code_book)[0] # Update the code book by computing centroids new_code_book, has_members = _vq.update_cluster_means(data, label, nc) if not has_members.all(): miss_meth() # Set the empty clusters to their previous positions new_code_book[~has_members] = code_book[~has_members] code_book = new_code_book return code_book, label
def eigh( a, b=None, lower=True, eigvals_only=False, overwrite_a=False, overwrite_b=False, turbo=True, eigvals=None, type=1, check_finite=True, ): """ Solve an ordinary or generalized eigenvalue problem for a complex Hermitian or real symmetric matrix. Find eigenvalues w and optionally eigenvectors v of matrix `a`, where `b` is positive definite:: a v[:,i] = w[i] b v[:,i] v[i,:].conj() a v[:,i] = w[i] v[i,:].conj() b v[:,i] = 1 Parameters ---------- a : (M, M) array_like A complex Hermitian or real symmetric matrix whose eigenvalues and eigenvectors will be computed. b : (M, M) array_like, optional A complex Hermitian or real symmetric definite positive matrix in. If omitted, identity matrix is assumed. lower : bool, optional Whether the pertinent array data is taken from the lower or upper triangle of `a`. (Default: lower) eigvals_only : bool, optional Whether to calculate only eigenvalues and no eigenvectors. (Default: both are calculated) turbo : bool, optional Use divide and conquer algorithm (faster but expensive in memory, only for generalized eigenvalue problem and if eigvals=None) eigvals : tuple (lo, hi), optional Indexes of the smallest and largest (in ascending order) eigenvalues and corresponding eigenvectors to be returned: 0 <= lo <= hi <= M-1. If omitted, all eigenvalues and eigenvectors are returned. type : int, optional Specifies the problem type to be solved: type = 1: a v[:,i] = w[i] b v[:,i] type = 2: a b v[:,i] = w[i] v[:,i] type = 3: b a v[:,i] = w[i] v[:,i] overwrite_a : bool, optional Whether to overwrite data in `a` (may improve performance) overwrite_b : bool, optional Whether to overwrite data in `b` (may improve performance) check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- w : (N,) float ndarray The N (1<=N<=M) selected eigenvalues, in ascending order, each repeated according to its multiplicity. v : (M, N) complex ndarray (if eigvals_only == False) The normalized selected eigenvector corresponding to the eigenvalue w[i] is the column v[:,i]. Normalization: type 1 and 3: v.conj() a v = w type 2: inv(v).conj() a inv(v) = w type = 1 or 2: v.conj() b v = I type = 3: v.conj() inv(b) v = I Raises ------ LinAlgError If eigenvalue computation does not converge, an error occurred, or b matrix is not definite positive. Note that if input matrices are not symmetric or hermitian, no error is reported but results will be wrong. See Also -------- eig : eigenvalues and right eigenvectors for non-symmetric arrays """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]: raise ValueError("expected square matrix") overwrite_a = overwrite_a or (_datacopied(a1, a)) if iscomplexobj(a1): cplx = True else: cplx = False if b is not None: b1 = _asarray_validated(b, check_finite=check_finite) overwrite_b = overwrite_b or _datacopied(b1, b) if len(b1.shape) != 2 or b1.shape[0] != b1.shape[1]: raise ValueError("expected square matrix") if b1.shape != a1.shape: raise ValueError("wrong b dimensions %s, should " "be %s" % (str(b1.shape), str(a1.shape))) if iscomplexobj(b1): cplx = True else: cplx = cplx or False else: b1 = None # Set job for fortran routines _job = (eigvals_only and "N") or "V" # port eigenvalue range from python to fortran convention if eigvals is not None: lo, hi = eigvals if lo < 0 or hi >= a1.shape[0]: raise ValueError( "The eigenvalue range specified is not valid.\n" "Valid range is [%s,%s]" % (0, a1.shape[0] - 1) ) lo += 1 hi += 1 eigvals = (lo, hi) # set lower if lower: uplo = "L" else: uplo = "U" # fix prefix for lapack routines if cplx: pfx = "he" else: pfx = "sy" # Standard Eigenvalue Problem # Use '*evr' routines # FIXME: implement calculation of optimal lwork # for all lapack routines if b1 is None: (evr,) = get_lapack_funcs((pfx + "evr",), (a1,)) if eigvals is None: w, v, info = evr(a1, uplo=uplo, jobz=_job, range="A", il=1, iu=a1.shape[0], overwrite_a=overwrite_a) else: (lo, hi) = eigvals w_tot, v, info = evr(a1, uplo=uplo, jobz=_job, range="I", il=lo, iu=hi, overwrite_a=overwrite_a) w = w_tot[0 : hi - lo + 1] # Generalized Eigenvalue Problem else: # Use '*gvx' routines if range is specified if eigvals is not None: (gvx,) = get_lapack_funcs((pfx + "gvx",), (a1, b1)) (lo, hi) = eigvals w_tot, v, ifail, info = gvx( a1, b1, uplo=uplo, iu=hi, itype=type, jobz=_job, il=lo, overwrite_a=overwrite_a, overwrite_b=overwrite_b ) w = w_tot[0 : hi - lo + 1] # Use '*gvd' routine if turbo is on and no eigvals are specified elif turbo: (gvd,) = get_lapack_funcs((pfx + "gvd",), (a1, b1)) v, w, info = gvd(a1, b1, uplo=uplo, itype=type, jobz=_job, overwrite_a=overwrite_a, overwrite_b=overwrite_b) # Use '*gv' routine if turbo is off and no eigvals are specified else: (gv,) = get_lapack_funcs((pfx + "gv",), (a1, b1)) v, w, info = gv(a1, b1, uplo=uplo, itype=type, jobz=_job, overwrite_a=overwrite_a, overwrite_b=overwrite_b) # Check if we had a successful exit if info == 0: if eigvals_only: return w else: return w, v elif info < 0: raise LinAlgError("illegal value in %i-th argument of internal" " fortran routine." % (-info)) elif info > 0 and b1 is None: raise LinAlgError("unrecoverable internal error.") # The algorithm failed to converge. elif 0 < info <= b1.shape[0]: if eigvals is not None: raise LinAlgError("the eigenvectors %s failed to" " converge." % nonzero(ifail) - 1) else: raise LinAlgError( "internal fortran routine failed to converge: " "%i off-diagonal elements of an " "intermediate tridiagonal form did not converge" " to zero." % info ) # This occurs when b is not positive definite else: raise LinAlgError( "the leading minor of order %i" " of 'b' is not positive definite. The" " factorization of 'b' could not be completed" " and no eigenvalues or eigenvectors were" " computed." % (info - b1.shape[0]) )
def _mul_triangular(c, b, trans=False, lower=True, overwrite_b=False, check_finite=True): """wrapper for BLAS function trmv to perform triangular matrix multiplications Parameters ---------- a : (M, M) array_like A triangular matrix b : (M,) or (M, N) array_like vector/matrix being multiplied lower : bool, optional Use only data contained in the lower triangle of `a`. Default is to use upper triangle. trans : bool, optional type of multiplication, ======== ========= trans system ======== ========= False a b True a^T b overwrite_b : bool, optional Allow overwriting data in `b` (may enhance performance) not fully tested check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. """ a1 = _asarray_validated(c, check_finite=check_finite) b1 = _asarray_validated(b, check_finite=check_finite) n = c.shape[1] if c.shape[0] != n: raise ValueError("Triangular matrix passed must be square") if b.shape[0] != n: raise ValueError(f"shapes {c.shape} and {b.shape} not aligned: " f"{n} (dim 1) != {b.shape[0]} (dim 0)") trmv, = get_blas_funcs(('trmv', ), (a1, b1)) if a1.flags.f_contiguous: def _trmv(a1, b1, overwrite_x): return trmv(a1, b1, lower=lower, trans=trans, overwrite_x=overwrite_x) else: # transposed system is solved since trmv expects Fortran ordering def _trmv(a1, b1, overwrite_x=overwrite_b): return trmv(a1.T, b1, lower=not lower, trans=not trans, overwrite_x=overwrite_x) if b1.ndim == 1: return _trmv(a1, b1, overwrite_b) elif b1.ndim == 2: # trmv only works for vector multiplications # set Fortran order so memory contiguous b2 = np.array(b1, order='F') for i in range(b2.shape[1]): # overwrite results _trmv(a1, b2[:, i], True) if overwrite_b: b1[:] = b2 return b1 else: return b2 else: raise ValueError("b must have 1 or 2 dimensions, has {b.ndim}")
def eig_banded(a_band, lower=False, eigvals_only=False, overwrite_a_band=False, select='a', select_range=None, max_ev=0, check_finite=True): """ Solve real symmetric or complex hermitian band matrix eigenvalue problem. Find eigenvalues w and optionally right eigenvectors v of a:: a v[:,i] = w[i] v[:,i] v.H v = identity The matrix a is stored in a_band either in lower diagonal or upper diagonal ordered form: a_band[u + i - j, j] == a[i,j] (if upper form; i <= j) a_band[ i - j, j] == a[i,j] (if lower form; i >= j) where u is the number of bands above the diagonal. Example of a_band (shape of a is (6,6), u=2):: upper form: * * a02 a13 a24 a35 * a01 a12 a23 a34 a45 a00 a11 a22 a33 a44 a55 lower form: a00 a11 a22 a33 a44 a55 a10 a21 a32 a43 a54 * a20 a31 a42 a53 * * Cells marked with * are not used. Parameters ---------- a_band : (u+1, M) array_like The bands of the M by M matrix a. lower : bool, optional Is the matrix in the lower form. (Default is upper form) eigvals_only : bool, optional Compute only the eigenvalues and no eigenvectors. (Default: calculate also eigenvectors) overwrite_a_band : bool, optional Discard data in a_band (may enhance performance) select : {'a', 'v', 'i'}, optional Which eigenvalues to calculate ====== ======================================== select calculated ====== ======================================== 'a' All eigenvalues 'v' Eigenvalues in the interval (min, max] 'i' Eigenvalues with indices min <= i <= max ====== ======================================== select_range : (min, max), optional Range of selected eigenvalues max_ev : int, optional For select=='v', maximum number of eigenvalues expected. For other values of select, has no meaning. In doubt, leave this parameter untouched. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- w : (M,) ndarray The eigenvalues, in ascending order, each repeated according to its multiplicity. v : (M, M) float or complex ndarray The normalized eigenvector corresponding to the eigenvalue w[i] is the column v[:,i]. Raises ------ LinAlgError If eigenvalue computation does not converge. See Also -------- eigvals_banded : eigenvalues for symmetric/Hermitian band matrices eig : eigenvalues and right eigenvectors of general arrays. eigh : eigenvalues and right eigenvectors for symmetric/Hermitian arrays eigh_tridiagonal : eigenvalues and right eiegenvectors for symmetric/Hermitian tridiagonal matrices Examples -------- >>> from scipy.linalg import eig_banded >>> A = np.array([[1, 5, 2, 0], [5, 2, 5, 2], [2, 5, 3, 5], [0, 2, 5, 4]]) >>> Ab = np.array([[1, 2, 3, 4], [5, 5, 5, 0], [2, 2, 0, 0]]) >>> w, v = eig_banded(Ab, lower=True) >>> np.allclose(A @ v - v @ np.diag(w), np.zeros((4, 4))) True >>> w = eig_banded(Ab, lower=True, eigvals_only=True) >>> w array([-4.26200532, -2.22987175, 3.95222349, 12.53965359]) Request only the eigenvalues between ``[-3, 4]`` >>> w, v = eig_banded(Ab, lower=True, select='v', select_range=[-3, 4]) >>> w array([-2.22987175, 3.95222349]) """ if eigvals_only or overwrite_a_band: a1 = _asarray_validated(a_band, check_finite=check_finite) overwrite_a_band = overwrite_a_band or (_datacopied(a1, a_band)) else: a1 = array(a_band) if issubclass(a1.dtype.type, inexact) and not isfinite(a1).all(): raise ValueError("array must not contain infs or NaNs") overwrite_a_band = 1 if len(a1.shape) != 2: raise ValueError('expected two-dimensional array') select, vl, vu, il, iu, max_ev = _check_select(select, select_range, max_ev, a1.shape[1]) del select_range if select == 0: if a1.dtype.char in 'GFD': # FIXME: implement this somewhen, for now go with builtin values # FIXME: calc optimal lwork by calling ?hbevd(lwork=-1) # or by using calc_lwork.f ??? # lwork = calc_lwork.hbevd(bevd.typecode, a1.shape[0], lower) internal_name = 'hbevd' else: # a1.dtype.char in 'fd': # FIXME: implement this somewhen, for now go with builtin values # see above # lwork = calc_lwork.sbevd(bevd.typecode, a1.shape[0], lower) internal_name = 'sbevd' bevd, = get_lapack_funcs((internal_name, ), (a1, )) w, v, info = bevd(a1, compute_v=not eigvals_only, lower=lower, overwrite_ab=overwrite_a_band) else: # select in [1, 2] if eigvals_only: max_ev = 1 # calculate optimal abstol for dsbevx (see manpage) if a1.dtype.char in 'fF': # single precision lamch, = get_lapack_funcs(('lamch', ), (array(0, dtype='f'), )) else: lamch, = get_lapack_funcs(('lamch', ), (array(0, dtype='d'), )) abstol = 2 * lamch('s') if a1.dtype.char in 'GFD': internal_name = 'hbevx' else: # a1.dtype.char in 'gfd' internal_name = 'sbevx' bevx, = get_lapack_funcs((internal_name, ), (a1, )) w, v, m, ifail, info = bevx(a1, vl, vu, il, iu, compute_v=not eigvals_only, mmax=max_ev, range=select, lower=lower, overwrite_ab=overwrite_a_band, abstol=abstol) # crop off w and v w = w[:m] if not eigvals_only: v = v[:, :m] _check_info(info, internal_name) if eigvals_only: return w return w, v
def py_vq(obs, code_book, check_finite=True): """ Python version of vq algorithm. The algorithm computes the euclidian distance between each observation and every frame in the code_book. Parameters ---------- obs : ndarray Expects a rank 2 array. Each row is one observation. code_book : ndarray Code book to use. Same format than obs. Should have same number of features (eg columns) than obs. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- code : ndarray code[i] gives the label of the ith obversation, that its code is code_book[code[i]]. mind_dist : ndarray min_dist[i] gives the distance between the ith observation and its corresponding code. Notes ----- This function is slower than the C version but works for all input types. If the inputs have the wrong types for the C versions of the function, this one is called as a last resort. It is about 20 times slower than the C version. """ obs = _asarray_validated(obs, check_finite=check_finite) code_book = _asarray_validated(code_book, check_finite=check_finite) # n = number of observations # d = number of features if np.ndim(obs) == 1: if not np.ndim(obs) == np.ndim(code_book): raise ValueError( "Observation and code_book should have the same rank") else: return _py_vq_1d(obs, code_book) else: (n, d) = shape(obs) # code books and observations should have same number of features and same # shape if not np.ndim(obs) == np.ndim(code_book): raise ValueError("Observation and code_book should have the same rank") elif not d == code_book.shape[1]: raise ValueError("Code book(%d) and obs(%d) should have the same " "number of features (eg columns)" "" % (code_book.shape[1], d)) code = zeros(n, dtype=int) min_dist = zeros(n) for i in range(n): dist = np.sum((obs[i] - code_book)**2, 1) code[i] = argmin(dist) min_dist[i] = dist[code[i]] return code, sqrt(min_dist)
def eig(a, b=None, left=False, right=True, overwrite_a=False, overwrite_b=False, check_finite=True, homogeneous_eigvals=False): """ Solve an ordinary or generalized eigenvalue problem of a square matrix. Find eigenvalues w and right or left eigenvectors of a general matrix:: a vr[:,i] = w[i] b vr[:,i] a.H vl[:,i] = w[i].conj() b.H vl[:,i] where ``.H`` is the Hermitian conjugation. Parameters ---------- a : (M, M) array_like A complex or real matrix whose eigenvalues and eigenvectors will be computed. b : (M, M) array_like, optional Right-hand side matrix in a generalized eigenvalue problem. Default is None, identity matrix is assumed. left : bool, optional Whether to calculate and return left eigenvectors. Default is False. right : bool, optional Whether to calculate and return right eigenvectors. Default is True. overwrite_a : bool, optional Whether to overwrite `a`; may improve performance. Default is False. overwrite_b : bool, optional Whether to overwrite `b`; may improve performance. Default is False. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. homogeneous_eigvals : bool, optional If True, return the eigenvalues in homogeneous coordinates. In this case ``w`` is a (2, M) array so that:: w[1,i] a vr[:,i] = w[0,i] b vr[:,i] Default is False. Returns ------- w : (M,) or (2, M) double or complex ndarray The eigenvalues, each repeated according to its multiplicity. The shape is (M,) unless ``homogeneous_eigvals=True``. vl : (M, M) double or complex ndarray The normalized left eigenvector corresponding to the eigenvalue ``w[i]`` is the column vl[:,i]. Only returned if ``left=True``. vr : (M, M) double or complex ndarray The normalized right eigenvector corresponding to the eigenvalue ``w[i]`` is the column ``vr[:,i]``. Only returned if ``right=True``. Raises ------ LinAlgError If eigenvalue computation does not converge. See Also -------- eigvals : eigenvalues of general arrays eigh : Eigenvalues and right eigenvectors for symmetric/Hermitian arrays. eig_banded : eigenvalues and right eigenvectors for symmetric/Hermitian band matrices eigh_tridiagonal : eigenvalues and right eiegenvectors for symmetric/Hermitian tridiagonal matrices Examples -------- >>> from scipy import linalg >>> a = np.array([[0., -1.], [1., 0.]]) >>> linalg.eigvals(a) array([0.+1.j, 0.-1.j]) >>> b = np.array([[0., 1.], [1., 1.]]) >>> linalg.eigvals(a, b) array([ 1.+0.j, -1.+0.j]) >>> a = np.array([[3., 0., 0.], [0., 8., 0.], [0., 0., 7.]]) >>> linalg.eigvals(a, homogeneous_eigvals=True) array([[3.+0.j, 8.+0.j, 7.+0.j], [1.+0.j, 1.+0.j, 1.+0.j]]) """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]: raise ValueError('expected square matrix') overwrite_a = overwrite_a or (_datacopied(a1, a)) if b is not None: b1 = _asarray_validated(b, check_finite=check_finite) overwrite_b = overwrite_b or _datacopied(b1, b) if len(b1.shape) != 2 or b1.shape[0] != b1.shape[1]: raise ValueError('expected square matrix') if b1.shape != a1.shape: raise ValueError('a and b must have the same shape') return _geneig(a1, b1, left, right, overwrite_a, overwrite_b, homogeneous_eigvals) geev, geev_lwork = get_lapack_funcs(('geev', 'geev_lwork'), (a1,)) compute_vl, compute_vr = left, right lwork = _compute_lwork(geev_lwork, a1.shape[0], compute_vl=compute_vl, compute_vr=compute_vr) if geev.typecode in 'cz': w, vl, vr, info = geev(a1, lwork=lwork, compute_vl=compute_vl, compute_vr=compute_vr, overwrite_a=overwrite_a) w = _make_eigvals(w, None, homogeneous_eigvals) else: wr, wi, vl, vr, info = geev(a1, lwork=lwork, compute_vl=compute_vl, compute_vr=compute_vr, overwrite_a=overwrite_a) t = {'f': 'F', 'd': 'D'}[wr.dtype.char] w = wr + _I * wi w = _make_eigvals(w, None, homogeneous_eigvals) _check_info(info, 'eig algorithm (geev)', positive='did not converge (only eigenvalues ' 'with order >= %d have converged)') only_real = numpy.all(w.imag == 0.0) if not (geev.typecode in 'cz' or only_real): t = w.dtype.char if left: vl = _make_complex_eigvecs(w, vl, t) if right: vr = _make_complex_eigvecs(w, vr, t) if not (left or right): return w if left: if right: return w, vl, vr return w, vl return w, vr
def kmeans2(data, k, iter=10, thresh=1e-5, minit='random', missing='warn', check_finite=True): """ Classify a set of observations into k clusters using the k-means algorithm. The algorithm attempts to minimize the Euclidian distance between observations and centroids. Several initialization methods are included. Parameters ---------- data : ndarray A 'M' by 'N' array of 'M' observations in 'N' dimensions or a length 'M' array of 'M' one-dimensional observations. k : int or ndarray The number of clusters to form as well as the number of centroids to generate. If `minit` initialization string is 'matrix', or if a ndarray is given instead, it is interpreted as initial cluster to use instead. iter : int, optional Number of iterations of the k-means algorithm to run. Note that this differs in meaning from the iters parameter to the kmeans function. thresh : float, optional (not used yet) minit : str, optional Method for initialization. Available methods are 'random', 'points', and 'matrix': 'random': generate k centroids from a Gaussian with mean and variance estimated from the data. 'points': choose k observations (rows) at random from data for the initial centroids. 'matrix': interpret the k parameter as a k by M (or length k array for one-dimensional data) array of initial centroids. missing : str, optional Method to deal with empty clusters. Available methods are 'warn' and 'raise': 'warn': give a warning and continue. 'raise': raise an ClusterError and terminate the algorithm. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- centroid : ndarray A 'k' by 'N' array of centroids found at the last iteration of k-means. label : ndarray label[i] is the code or index of the centroid the i'th observation is closest to. """ if int(iter) < 1: raise ValueError("Invalid iter (%s), " "must be a positive integer." % iter) try: miss_meth = _valid_miss_meth[missing] except KeyError: raise ValueError("Unknown missing method %r" % (missing, )) data = _asarray_validated(data, check_finite=check_finite) if data.ndim == 1: d = 1 elif data.ndim == 2: d = data.shape[1] else: raise ValueError("Input of rank > 2 is not supported.") if data.size < 1: raise ValueError("Empty input is not supported.") # If k is not a single value it should be compatible with data's shape if minit == 'matrix' or not np.isscalar(k): code_book = np.array(k, copy=True) if data.ndim != code_book.ndim: raise ValueError("k array doesn't match data rank") nc = len(code_book) if data.ndim > 1 and code_book.shape[1] != d: raise ValueError("k array doesn't match data dimension") else: nc = int(k) if nc < 1: raise ValueError("Cannot ask kmeans2 for %d clusters" " (k was %s)" % (nc, k)) elif nc != k: warnings.warn("k was not an integer, was converted.") try: init_meth = _valid_init_meth[minit] except KeyError: raise ValueError("Unknown init method %r" % (minit, )) else: code_book = init_meth(data, k) for i in xrange(iter): # Compute the nearest neighbor for each obs using the current code book label = vq(data, code_book)[0] # Update the code book by computing centroids new_code_book, has_members = _vq.update_cluster_means(data, label, nc) if not has_members.all(): miss_meth() # Set the empty clusters to their previous positions new_code_book[~has_members] = code_book[~has_members] code_book = new_code_book return code_book, label
def softmax(x, axis=None): r"""Compute the softmax function. The softmax function transforms each element of a collection by computing the exponential of each element divided by the sum of the exponentials of all the elements. That is, if `x` is a one-dimensional numpy array:: softmax(x) = np.exp(x)/sum(np.exp(x)) Parameters ---------- x : array_like Input array. axis : int or tuple of ints, optional Axis to compute values along. Default is None and softmax will be computed over the entire array `x`. Returns ------- s : ndarray An array the same shape as `x`. The result will sum to 1 along the specified axis. Notes ----- The formula for the softmax function :math:`\sigma(x)` for a vector :math:`x = \{x_0, x_1, ..., x_{n-1}\}` is .. math:: \sigma(x)_j = \frac{e^{x_j}}{\sum_k e^{x_k}} The `softmax` function is the gradient of `logsumexp`. The implementation uses shifting to avoid overflow. See [1]_ for more details. .. versionadded:: 1.2.0 References ---------- .. [1] P. Blanchard, D.J. Higham, N.J. Higham, "Accurately computing the log-sum-exp and softmax functions", IMA Journal of Numerical Analysis, Vol.41(4), :doi:`10.1093/imanum/draa038`. Examples -------- >>> from scipy.special import softmax >>> np.set_printoptions(precision=5) >>> x = np.array([[1, 0.5, 0.2, 3], ... [1, -1, 7, 3], ... [2, 12, 13, 3]]) ... Compute the softmax transformation over the entire array. >>> m = softmax(x) >>> m array([[ 4.48309e-06, 2.71913e-06, 2.01438e-06, 3.31258e-05], [ 4.48309e-06, 6.06720e-07, 1.80861e-03, 3.31258e-05], [ 1.21863e-05, 2.68421e-01, 7.29644e-01, 3.31258e-05]]) >>> m.sum() 1.0 Compute the softmax transformation along the first axis (i.e., the columns). >>> m = softmax(x, axis=0) >>> m array([[ 2.11942e-01, 1.01300e-05, 2.75394e-06, 3.33333e-01], [ 2.11942e-01, 2.26030e-06, 2.47262e-03, 3.33333e-01], [ 5.76117e-01, 9.99988e-01, 9.97525e-01, 3.33333e-01]]) >>> m.sum(axis=0) array([ 1., 1., 1., 1.]) Compute the softmax transformation along the second axis (i.e., the rows). >>> m = softmax(x, axis=1) >>> m array([[ 1.05877e-01, 6.42177e-02, 4.75736e-02, 7.82332e-01], [ 2.42746e-03, 3.28521e-04, 9.79307e-01, 1.79366e-02], [ 1.22094e-05, 2.68929e-01, 7.31025e-01, 3.31885e-05]]) >>> m.sum(axis=1) array([ 1., 1., 1.]) """ x = _asarray_validated(x, check_finite=False) x_max = np.amax(x, axis=axis, keepdims=True) exp_x_shifted = np.exp(x - x_max) return exp_x_shifted / np.sum(exp_x_shifted, axis=axis, keepdims=True)
def eig(a, b=None, left=False, right=True, overwrite_a=False, overwrite_b=False, check_finite=True): """ Solve an ordinary or generalized eigenvalue problem of a square matrix. Find eigenvalues w and right or left eigenvectors of a general matrix:: a vr[:,i] = w[i] b vr[:,i] a.H vl[:,i] = w[i].conj() b.H vl[:,i] where ``.H`` is the Hermitian conjugation. Parameters ---------- a : (M, M) array_like A complex or real matrix whose eigenvalues and eigenvectors will be computed. b : (M, M) array_like, optional Right-hand side matrix in a generalized eigenvalue problem. Default is None, identity matrix is assumed. left : bool, optional Whether to calculate and return left eigenvectors. Default is False. right : bool, optional Whether to calculate and return right eigenvectors. Default is True. overwrite_a : bool, optional Whether to overwrite `a`; may improve performance. Default is False. overwrite_b : bool, optional Whether to overwrite `b`; may improve performance. Default is False. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- w : (M,) double or complex ndarray The eigenvalues, each repeated according to its multiplicity. vl : (M, M) double or complex ndarray The normalized left eigenvector corresponding to the eigenvalue ``w[i]`` is the column vl[:,i]. Only returned if ``left=True``. vr : (M, M) double or complex ndarray The normalized right eigenvector corresponding to the eigenvalue ``w[i]`` is the column ``vr[:,i]``. Only returned if ``right=True``. Raises ------ LinAlgError If eigenvalue computation does not converge. See Also -------- eigh : Eigenvalues and right eigenvectors for symmetric/Hermitian arrays. """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]: raise ValueError("expected square matrix") overwrite_a = overwrite_a or (_datacopied(a1, a)) if b is not None: b1 = _asarray_validated(b, check_finite=check_finite) overwrite_b = overwrite_b or _datacopied(b1, b) if len(b1.shape) != 2 or b1.shape[0] != b1.shape[1]: raise ValueError("expected square matrix") if b1.shape != a1.shape: raise ValueError("a and b must have the same shape") return _geneig(a1, b1, left, right, overwrite_a, overwrite_b) geev, geev_lwork = get_lapack_funcs(("geev", "geev_lwork"), (a1,)) compute_vl, compute_vr = left, right lwork = _compute_lwork(geev_lwork, a1.shape[0], compute_vl=compute_vl, compute_vr=compute_vr) if geev.typecode in "cz": w, vl, vr, info = geev(a1, lwork=lwork, compute_vl=compute_vl, compute_vr=compute_vr, overwrite_a=overwrite_a) else: wr, wi, vl, vr, info = geev( a1, lwork=lwork, compute_vl=compute_vl, compute_vr=compute_vr, overwrite_a=overwrite_a ) t = {"f": "F", "d": "D"}[wr.dtype.char] w = wr + _I * wi if info < 0: raise ValueError("illegal value in %d-th argument of internal geev" % -info) if info > 0: raise LinAlgError("eig algorithm did not converge (only eigenvalues " "with order >= %d have converged)" % info) only_real = numpy.logical_and.reduce(numpy.equal(w.imag, 0.0)) if not (geev.typecode in "cz" or only_real): t = w.dtype.char if left: vl = _make_complex_eigvecs(w, vl, t) if right: vr = _make_complex_eigvecs(w, vr, t) if not (left or right): return w if left: if right: return w, vl, vr return w, vl return w, vr
def hessenberg(a, calc_q=False, overwrite_a=False, check_finite=True): """ Compute Hessenberg form of a matrix. The Hessenberg decomposition is:: A = Q H Q^H where `Q` is unitary/orthogonal and `H` has only zero elements below the first sub-diagonal. Parameters ---------- a : (M, M) array_like Matrix to bring into Hessenberg form. calc_q : bool, optional Whether to compute the transformation matrix. Default is False. overwrite_a : bool, optional Whether to overwrite `a`; may improve performance. Default is False. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- H : (M, M) ndarray Hessenberg form of `a`. Q : (M, M) ndarray Unitary/orthogonal similarity transformation matrix ``A = Q H Q^H``. Only returned if ``calc_q=True``. """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2 or (a1.shape[0] != a1.shape[1]): raise ValueError("expected square matrix") overwrite_a = overwrite_a or (_datacopied(a1, a)) # if 2x2 or smaller: already in Hessenberg if a1.shape[0] <= 2: if calc_q: return a1, numpy.eye(a1.shape[0]) return a1 gehrd, gebal, gehrd_lwork = get_lapack_funcs(("gehrd", "gebal", "gehrd_lwork"), (a1,)) ba, lo, hi, pivscale, info = gebal(a1, permute=0, overwrite_a=overwrite_a) if info < 0: raise ValueError("illegal value in %d-th argument of internal gebal " "(hessenberg)" % -info) n = len(a1) lwork = _compute_lwork(gehrd_lwork, ba.shape[0], lo=lo, hi=hi) hq, tau, info = gehrd(ba, lo=lo, hi=hi, lwork=lwork, overwrite_a=1) if info < 0: raise ValueError("illegal value in %d-th argument of internal gehrd " "(hessenberg)" % -info) h = numpy.triu(hq, -1) if not calc_q: return h # use orghr/unghr to compute q orghr, orghr_lwork = get_lapack_funcs(("orghr", "orghr_lwork"), (a1,)) lwork = _compute_lwork(orghr_lwork, n, lo=lo, hi=hi) q, info = orghr(a=hq, tau=tau, lo=lo, hi=hi, lwork=lwork, overwrite_a=1) if info < 0: raise ValueError("illegal value in %d-th argument of internal orghr " "(hessenberg)" % -info) return h, q
def eig_banded( a_band, lower=False, eigvals_only=False, overwrite_a_band=False, select="a", select_range=None, max_ev=0, check_finite=True, ): """ Solve real symmetric or complex hermitian band matrix eigenvalue problem. Find eigenvalues w and optionally right eigenvectors v of a:: a v[:,i] = w[i] v[:,i] v.H v = identity The matrix a is stored in a_band either in lower diagonal or upper diagonal ordered form: a_band[u + i - j, j] == a[i,j] (if upper form; i <= j) a_band[ i - j, j] == a[i,j] (if lower form; i >= j) where u is the number of bands above the diagonal. Example of a_band (shape of a is (6,6), u=2):: upper form: * * a02 a13 a24 a35 * a01 a12 a23 a34 a45 a00 a11 a22 a33 a44 a55 lower form: a00 a11 a22 a33 a44 a55 a10 a21 a32 a43 a54 * a20 a31 a42 a53 * * Cells marked with * are not used. Parameters ---------- a_band : (u+1, M) array_like The bands of the M by M matrix a. lower : bool, optional Is the matrix in the lower form. (Default is upper form) eigvals_only : bool, optional Compute only the eigenvalues and no eigenvectors. (Default: calculate also eigenvectors) overwrite_a_band : bool, optional Discard data in a_band (may enhance performance) select : {'a', 'v', 'i'}, optional Which eigenvalues to calculate ====== ======================================== select calculated ====== ======================================== 'a' All eigenvalues 'v' Eigenvalues in the interval (min, max] 'i' Eigenvalues with indices min <= i <= max ====== ======================================== select_range : (min, max), optional Range of selected eigenvalues max_ev : int, optional For select=='v', maximum number of eigenvalues expected. For other values of select, has no meaning. In doubt, leave this parameter untouched. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- w : (M,) ndarray The eigenvalues, in ascending order, each repeated according to its multiplicity. v : (M, M) float or complex ndarray The normalized eigenvector corresponding to the eigenvalue w[i] is the column v[:,i]. Raises LinAlgError if eigenvalue computation does not converge """ if eigvals_only or overwrite_a_band: a1 = _asarray_validated(a_band, check_finite=check_finite) overwrite_a_band = overwrite_a_band or (_datacopied(a1, a_band)) else: a1 = array(a_band) if issubclass(a1.dtype.type, inexact) and not isfinite(a1).all(): raise ValueError("array must not contain infs or NaNs") overwrite_a_band = 1 if len(a1.shape) != 2: raise ValueError("expected two-dimensional array") if select.lower() not in [0, 1, 2, "a", "v", "i", "all", "value", "index"]: raise ValueError("invalid argument for select") if select.lower() in [0, "a", "all"]: if a1.dtype.char in "GFD": bevd, = get_lapack_funcs(("hbevd",), (a1,)) # FIXME: implement this somewhen, for now go with builtin values # FIXME: calc optimal lwork by calling ?hbevd(lwork=-1) # or by using calc_lwork.f ??? # lwork = calc_lwork.hbevd(bevd.typecode, a1.shape[0], lower) internal_name = "hbevd" else: # a1.dtype.char in 'fd': bevd, = get_lapack_funcs(("sbevd",), (a1,)) # FIXME: implement this somewhen, for now go with builtin values # see above # lwork = calc_lwork.sbevd(bevd.typecode, a1.shape[0], lower) internal_name = "sbevd" w, v, info = bevd(a1, compute_v=not eigvals_only, lower=lower, overwrite_ab=overwrite_a_band) if select.lower() in [1, 2, "i", "v", "index", "value"]: # calculate certain range only if select.lower() in [2, "i", "index"]: select = 2 vl, vu, il, iu = 0.0, 0.0, min(select_range), max(select_range) if min(il, iu) < 0 or max(il, iu) >= a1.shape[1]: raise ValueError("select_range out of bounds") max_ev = iu - il + 1 else: # 1, 'v', 'value' select = 1 vl, vu, il, iu = min(select_range), max(select_range), 0, 0 if max_ev == 0: max_ev = a_band.shape[1] if eigvals_only: max_ev = 1 # calculate optimal abstol for dsbevx (see manpage) if a1.dtype.char in "fF": # single precision lamch, = get_lapack_funcs(("lamch",), (array(0, dtype="f"),)) else: lamch, = get_lapack_funcs(("lamch",), (array(0, dtype="d"),)) abstol = 2 * lamch("s") if a1.dtype.char in "GFD": bevx, = get_lapack_funcs(("hbevx",), (a1,)) internal_name = "hbevx" else: # a1.dtype.char in 'gfd' bevx, = get_lapack_funcs(("sbevx",), (a1,)) internal_name = "sbevx" # il+1, iu+1: translate python indexing (0 ... N-1) into Fortran # indexing (1 ... N) w, v, m, ifail, info = bevx( a1, vl, vu, il + 1, iu + 1, compute_v=not eigvals_only, mmax=max_ev, range=select, lower=lower, overwrite_ab=overwrite_a_band, abstol=abstol, ) # crop off w and v w = w[:m] if not eigvals_only: v = v[:, :m] if info < 0: raise ValueError("illegal value in %d-th argument of internal %s" % (-info, internal_name)) if info > 0: raise LinAlgError("eig algorithm did not converge") if eigvals_only: return w return w, v
def kmeans(obs, k_or_guess, iter=20, thresh=1e-5, check_finite=True): """ Performs k-means on a set of observation vectors forming k clusters. The k-means algorithm adjusts the centroids until sufficient progress cannot be made, i.e. the change in distortion since the last iteration is less than some threshold. This yields a code book mapping centroids to codes and vice versa. Distortion is defined as the sum of the squared differences between the observations and the corresponding centroid. Parameters ---------- obs : ndarray Each row of the M by N array is an observation vector. The columns are the features seen during each observation. The features must be whitened first with the `whiten` function. k_or_guess : int or ndarray The number of centroids to generate. A code is assigned to each centroid, which is also the row index of the centroid in the code_book matrix generated. The initial k centroids are chosen by randomly selecting observations from the observation matrix. Alternatively, passing a k by N array specifies the initial k centroids. iter : int, optional The number of times to run k-means, returning the codebook with the lowest distortion. This argument is ignored if initial centroids are specified with an array for the ``k_or_guess`` parameter. This parameter does not represent the number of iterations of the k-means algorithm. thresh : float, optional Terminates the k-means algorithm if the change in distortion since the last k-means iteration is less than or equal to thresh. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- codebook : ndarray A k by N array of k centroids. The i'th centroid codebook[i] is represented with the code i. The centroids and codes generated represent the lowest distortion seen, not necessarily the globally minimal distortion. distortion : float The distortion between the observations passed and the centroids generated. See Also -------- kmeans2 : a different implementation of k-means clustering with more methods for generating initial centroids but without using a distortion change threshold as a stopping criterion. whiten : must be called prior to passing an observation matrix to kmeans. Examples -------- >>> from numpy import array >>> from scipy.cluster.vq import vq, kmeans, whiten >>> features = array([[ 1.9,2.3], ... [ 1.5,2.5], ... [ 0.8,0.6], ... [ 0.4,1.8], ... [ 0.1,0.1], ... [ 0.2,1.8], ... [ 2.0,0.5], ... [ 0.3,1.5], ... [ 1.0,1.0]]) >>> whitened = whiten(features) >>> book = array((whitened[0],whitened[2])) >>> kmeans(whitened,book) (array([[ 2.3110306 , 2.86287398], # random [ 0.93218041, 1.24398691]]), 0.85684700941625547) >>> from numpy import random >>> random.seed((1000,2000)) >>> codes = 3 >>> kmeans(whitened,codes) (array([[ 2.3110306 , 2.86287398], # random [ 1.32544402, 0.65607529], [ 0.40782893, 2.02786907]]), 0.5196582527686241) """ obs = _asarray_validated(obs, check_finite=check_finite) if int(iter) < 1: raise ValueError('iter must be at least 1.') # Determine whether a count (scalar) or an initial guess (array) was passed. k = None guess = None try: k = int(k_or_guess) except TypeError: guess = _asarray_validated(k_or_guess, check_finite=check_finite) if guess is not None: if guess.size < 1: raise ValueError("Asked for 0 cluster ? initial book was %s" % guess) result = _kmeans(obs, guess, thresh=thresh) else: if k != k_or_guess: raise ValueError('if k_or_guess is a scalar, it must be an integer') # initialize best distance value to a large value best_dist = np.inf No = obs.shape[0] k = k_or_guess if k < 1: raise ValueError("Asked for 0 cluster ? ") for i in range(iter): # the initial code book is randomly selected from observations guess = take(obs, randint(0, No, k), 0) book, dist = _kmeans(obs, guess, thresh=thresh) if dist < best_dist: best_book = book best_dist = dist result = best_book, best_dist return result
def kmeans2(data, k, iter=10, thresh=1e-5, minit='random', missing='warn', check_finite=True): """ Classify a set of observations into k clusters using the k-means algorithm. The algorithm attempts to minimize the Euclidian distance between observations and centroids. Several initialization methods are included. Parameters ---------- data : ndarray A 'M' by 'N' array of 'M' observations in 'N' dimensions or a length 'M' array of 'M' one-dimensional observations. k : int or ndarray The number of clusters to form as well as the number of centroids to generate. If `minit` initialization string is 'matrix', or if a ndarray is given instead, it is interpreted as initial cluster to use instead. iter : int, optional Number of iterations of the k-means algorithm to run. Note that this differs in meaning from the iters parameter to the kmeans function. thresh : float, optional (not used yet) minit : str, optional Method for initialization. Available methods are 'random', 'points', and 'matrix': 'random': generate k centroids from a Gaussian with mean and variance estimated from the data. 'points': choose k observations (rows) at random from data for the initial centroids. 'matrix': interpret the k parameter as a k by M (or length k array for one-dimensional data) array of initial centroids. missing : str, optional Method to deal with empty clusters. Available methods are 'warn' and 'raise': 'warn': give a warning and continue. 'raise': raise an ClusterError and terminate the algorithm. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- centroid : ndarray A 'k' by 'N' array of centroids found at the last iteration of k-means. label : ndarray label[i] is the code or index of the centroid the i'th observation is closest to. """ if int(iter) < 1: raise ValueError("Invalid iter (%s), " "must be a positive integer." % iter) try: miss_meth = _valid_miss_meth[missing] except KeyError: raise ValueError("Unknown missing method %r" % (missing,)) data = _asarray_validated(data, check_finite=check_finite) if data.ndim == 1: d = 1 elif data.ndim == 2: d = data.shape[1] else: raise ValueError("Input of rank > 2 is not supported.") if data.size < 1: raise ValueError("Empty input is not supported.") # If k is not a single value it should be compatible with data's shape if minit == 'matrix' or not np.isscalar(k): code_book = np.array(k, copy=True) if data.ndim != code_book.ndim: raise ValueError("k array doesn't match data rank") nc = len(code_book) if data.ndim > 1 and code_book.shape[1] != d: raise ValueError("k array doesn't match data dimension") else: nc = int(k) if nc < 1: raise ValueError("Cannot ask kmeans2 for %d clusters" " (k was %s)" % (nc, k)) elif nc != k: warnings.warn("k was not an integer, was converted.") try: init_meth = _valid_init_meth[minit] except KeyError: raise ValueError("Unknown init method %r" % (minit,)) else: code_book = init_meth(data, k) for i in xrange(iter): # Compute the nearest neighbor for each obs using the current code book label = vq(data, code_book)[0] # Update the code book by computing centroids new_code_book, has_members = _vq.update_cluster_means(data, label, nc) if not has_members.all(): miss_meth() # Set the empty clusters to their previous positions new_code_book[~has_members] = code_book[~has_members] code_book = new_code_book return code_book, label
def kmeans2(data, k, iter=10, thresh=1e-5, minit='random', missing='warn', check_finite=True): """ Classify a set of observations into k clusters using the k-means algorithm. The algorithm attempts to minimize the Euclidian distance between observations and centroids. Several initialization methods are included. Parameters ---------- data : ndarray A 'M' by 'N' array of 'M' observations in 'N' dimensions or a length 'M' array of 'M' one-dimensional observations. k : int or ndarray The number of clusters to form as well as the number of centroids to generate. If `minit` initialization string is 'matrix', or if a ndarray is given instead, it is interpreted as initial cluster to use instead. iter : int, optional Number of iterations of the k-means algrithm to run. Note that this differs in meaning from the iters parameter to the kmeans function. thresh : float, optional (not used yet) minit : str, optional Method for initialization. Available methods are 'random', 'points', 'uniform', and 'matrix': 'random': generate k centroids from a Gaussian with mean and variance estimated from the data. 'points': choose k observations (rows) at random from data for the initial centroids. 'uniform': generate k observations from the data from a uniform distribution defined by the data set (unsupported). 'matrix': interpret the k parameter as a k by M (or length k array for one-dimensional data) array of initial centroids. missing : str, optional Method to deal with empty clusters. Available methods are 'warn' and 'raise': 'warn': give a warning and continue. 'raise': raise an ClusterError and terminate the algorithm. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- centroid : ndarray A 'k' by 'N' array of centroids found at the last iteration of k-means. label : ndarray label[i] is the code or index of the centroid the i'th observation is closest to. """ data = _asarray_validated(data, check_finite=check_finite) if missing not in _valid_miss_meth: raise ValueError("Unkown missing method: %s" % str(missing)) # If data is rank 1, then we have 1 dimension problem. nd = np.ndim(data) if nd == 1: d = 1 # raise ValueError("Input of rank 1 not supported yet") elif nd == 2: d = data.shape[1] else: raise ValueError("Input of rank > 2 not supported") if np.size(data) < 1: raise ValueError("Input has 0 items.") # If k is not a single value, then it should be compatible with data's # shape if np.size(k) > 1 or minit == 'matrix': if not nd == np.ndim(k): raise ValueError("k is not an int and has not same rank than data") if d == 1: nc = len(k) else: (nc, dc) = k.shape if not dc == d: raise ValueError("k is not an int and has not same rank than\ data") clusters = k.copy() else: try: nc = int(k) except TypeError: raise ValueError("k (%s) could not be converted to an integer " % str(k)) if nc < 1: raise ValueError("kmeans2 for 0 clusters ? (k was %s)" % str(k)) if not nc == k: warnings.warn("k was not an integer, was converted.") try: init = _valid_init_meth[minit] except KeyError: raise ValueError("unknown init method %s" % str(minit)) clusters = init(data, k) if int(iter) < 1: raise ValueError("iter = %s is not valid. iter must be a positive integer." % iter) return _kmeans2(data, clusters, iter, nc, _valid_miss_meth[missing])
def eig(a, b=None, left=False, right=True, overwrite_a=False, overwrite_b=False, check_finite=True, homogeneous_eigvals=False): """ Solve an ordinary or generalized eigenvalue problem of a square matrix. Find eigenvalues w and right or left eigenvectors of a general matrix:: a vr[:,i] = w[i] b vr[:,i] a.H vl[:,i] = w[i].conj() b.H vl[:,i] where ``.H`` is the Hermitian conjugation. Parameters ---------- a : (M, M) array_like A complex or real matrix whose eigenvalues and eigenvectors will be computed. b : (M, M) array_like, optional Right-hand side matrix in a generalized eigenvalue problem. Default is None, identity matrix is assumed. left : bool, optional Whether to calculate and return left eigenvectors. Default is False. right : bool, optional Whether to calculate and return right eigenvectors. Default is True. overwrite_a : bool, optional Whether to overwrite `a`; may improve performance. Default is False. overwrite_b : bool, optional Whether to overwrite `b`; may improve performance. Default is False. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. homogeneous_eigvals : bool, optional If True, return the eigenvalues in homogeneous coordinates. In this case ``w`` is a (2, M) array so that:: w[1,i] a vr[:,i] = w[0,i] b vr[:,i] Default is False. Returns ------- w : (M,) or (2, M) double or complex ndarray The eigenvalues, each repeated according to its multiplicity. The shape is (M,) unless ``homogeneous_eigvals=True``. vl : (M, M) double or complex ndarray The normalized left eigenvector corresponding to the eigenvalue ``w[i]`` is the column vl[:,i]. Only returned if ``left=True``. vr : (M, M) double or complex ndarray The normalized right eigenvector corresponding to the eigenvalue ``w[i]`` is the column ``vr[:,i]``. Only returned if ``right=True``. Raises ------ LinAlgError If eigenvalue computation does not converge. See Also -------- eigh : Eigenvalues and right eigenvectors for symmetric/Hermitian arrays. """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]: raise ValueError('expected square matrix') overwrite_a = overwrite_a or (_datacopied(a1, a)) if b is not None: b1 = _asarray_validated(b, check_finite=check_finite) overwrite_b = overwrite_b or _datacopied(b1, b) if len(b1.shape) != 2 or b1.shape[0] != b1.shape[1]: raise ValueError('expected square matrix') if b1.shape != a1.shape: raise ValueError('a and b must have the same shape') return _geneig(a1, b1, left, right, overwrite_a, overwrite_b, homogeneous_eigvals) geev, geev_lwork = get_lapack_funcs(('geev', 'geev_lwork'), (a1, )) compute_vl, compute_vr = left, right lwork = _compute_lwork(geev_lwork, a1.shape[0], compute_vl=compute_vl, compute_vr=compute_vr) if geev.typecode in 'cz': w, vl, vr, info = geev(a1, lwork=lwork, compute_vl=compute_vl, compute_vr=compute_vr, overwrite_a=overwrite_a) w = _make_eigvals(w, None, homogeneous_eigvals) else: wr, wi, vl, vr, info = geev(a1, lwork=lwork, compute_vl=compute_vl, compute_vr=compute_vr, overwrite_a=overwrite_a) t = {'f': 'F', 'd': 'D'}[wr.dtype.char] w = wr + _I * wi w = _make_eigvals(w, None, homogeneous_eigvals) if info < 0: raise ValueError('illegal value in %d-th argument of internal geev' % -info) if info > 0: raise LinAlgError("eig algorithm did not converge (only eigenvalues " "with order >= %d have converged)" % info) only_real = numpy.all(w.imag == 0.0) if not (geev.typecode in 'cz' or only_real): t = w.dtype.char if left: vl = _make_complex_eigvecs(w, vl, t) if right: vr = _make_complex_eigvecs(w, vr, t) if not (left or right): return w if left: if right: return w, vl, vr return w, vl return w, vr
def vq(obs, code_book, check_finite=True): """ Assign codes from a code book to observations. Assigns a code from a code book to each observation. Each observation vector in the 'M' by 'N' `obs` array is compared with the centroids in the code book and assigned the code of the closest centroid. The features in `obs` should have unit variance, which can be achieved by passing them through the whiten function. The code book can be created with the k-means algorithm or a different encoding algorithm. Parameters ---------- obs : ndarray Each row of the 'M' x 'N' array is an observation. The columns are the "features" seen during each observation. The features must be whitened first using the whiten function or something equivalent. code_book : ndarray The code book is usually generated using the k-means algorithm. Each row of the array holds a different code, and the columns are the features of the code. >>> # f0 f1 f2 f3 >>> code_book = [ ... [ 1., 2., 3., 4.], #c0 ... [ 1., 2., 3., 4.], #c1 ... [ 1., 2., 3., 4.]] #c2 check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- code : ndarray A length M array holding the code book index for each observation. dist : ndarray The distortion (distance) between the observation and its nearest code. Examples -------- >>> from numpy import array >>> from scipy.cluster.vq import vq >>> code_book = array([[1.,1.,1.], ... [2.,2.,2.]]) >>> features = array([[ 1.9,2.3,1.7], ... [ 1.5,2.5,2.2], ... [ 0.8,0.6,1.7]]) >>> vq(features,code_book) (array([1, 1, 0],'i'), array([ 0.43588989, 0.73484692, 0.83066239])) """ obs = _asarray_validated(obs, check_finite=check_finite) code_book = _asarray_validated(code_book, check_finite=check_finite) ct = np.common_type(obs, code_book) c_obs = obs.astype(ct, copy=False) c_code_book = code_book.astype(ct, copy=False) if np.issubdtype(ct, np.float64) or np.issubdtype(ct, np.float32): return _vq.vq(c_obs, c_code_book) return py_vq(obs, code_book, check_finite=False)
def eig_banded(a_band, lower=False, eigvals_only=False, overwrite_a_band=False, select='a', select_range=None, max_ev=0, check_finite=True): """ Solve real symmetric or complex hermitian band matrix eigenvalue problem. Find eigenvalues w and optionally right eigenvectors v of a:: a v[:,i] = w[i] v[:,i] v.H v = identity The matrix a is stored in a_band either in lower diagonal or upper diagonal ordered form: a_band[u + i - j, j] == a[i,j] (if upper form; i <= j) a_band[ i - j, j] == a[i,j] (if lower form; i >= j) where u is the number of bands above the diagonal. Example of a_band (shape of a is (6,6), u=2):: upper form: * * a02 a13 a24 a35 * a01 a12 a23 a34 a45 a00 a11 a22 a33 a44 a55 lower form: a00 a11 a22 a33 a44 a55 a10 a21 a32 a43 a54 * a20 a31 a42 a53 * * Cells marked with * are not used. Parameters ---------- a_band : (u+1, M) array_like The bands of the M by M matrix a. lower : bool, optional Is the matrix in the lower form. (Default is upper form) eigvals_only : bool, optional Compute only the eigenvalues and no eigenvectors. (Default: calculate also eigenvectors) overwrite_a_band : bool, optional Discard data in a_band (may enhance performance) select : {'a', 'v', 'i'}, optional Which eigenvalues to calculate ====== ======================================== select calculated ====== ======================================== 'a' All eigenvalues 'v' Eigenvalues in the interval (min, max] 'i' Eigenvalues with indices min <= i <= max ====== ======================================== select_range : (min, max), optional Range of selected eigenvalues max_ev : int, optional For select=='v', maximum number of eigenvalues expected. For other values of select, has no meaning. In doubt, leave this parameter untouched. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- w : (M,) ndarray The eigenvalues, in ascending order, each repeated according to its multiplicity. v : (M, M) float or complex ndarray The normalized eigenvector corresponding to the eigenvalue w[i] is the column v[:,i]. Raises LinAlgError if eigenvalue computation does not converge """ if eigvals_only or overwrite_a_band: a1 = _asarray_validated(a_band, check_finite=check_finite) overwrite_a_band = overwrite_a_band or (_datacopied(a1, a_band)) else: a1 = array(a_band) if issubclass(a1.dtype.type, inexact) and not isfinite(a1).all(): raise ValueError("array must not contain infs or NaNs") overwrite_a_band = 1 if len(a1.shape) != 2: raise ValueError('expected two-dimensional array') if select.lower() not in [0, 1, 2, 'a', 'v', 'i', 'all', 'value', 'index']: raise ValueError('invalid argument for select') if select.lower() in [0, 'a', 'all']: if a1.dtype.char in 'GFD': bevd, = get_lapack_funcs(('hbevd', ), (a1, )) # FIXME: implement this somewhen, for now go with builtin values # FIXME: calc optimal lwork by calling ?hbevd(lwork=-1) # or by using calc_lwork.f ??? # lwork = calc_lwork.hbevd(bevd.typecode, a1.shape[0], lower) internal_name = 'hbevd' else: # a1.dtype.char in 'fd': bevd, = get_lapack_funcs(('sbevd', ), (a1, )) # FIXME: implement this somewhen, for now go with builtin values # see above # lwork = calc_lwork.sbevd(bevd.typecode, a1.shape[0], lower) internal_name = 'sbevd' w, v, info = bevd(a1, compute_v=not eigvals_only, lower=lower, overwrite_ab=overwrite_a_band) if select.lower() in [1, 2, 'i', 'v', 'index', 'value']: # calculate certain range only if select.lower() in [2, 'i', 'index']: select = 2 vl, vu, il, iu = 0.0, 0.0, min(select_range), max(select_range) if min(il, iu) < 0 or max(il, iu) >= a1.shape[1]: raise ValueError('select_range out of bounds') max_ev = iu - il + 1 else: # 1, 'v', 'value' select = 1 vl, vu, il, iu = min(select_range), max(select_range), 0, 0 if max_ev == 0: max_ev = a_band.shape[1] if eigvals_only: max_ev = 1 # calculate optimal abstol for dsbevx (see manpage) if a1.dtype.char in 'fF': # single precision lamch, = get_lapack_funcs(('lamch', ), (array(0, dtype='f'), )) else: lamch, = get_lapack_funcs(('lamch', ), (array(0, dtype='d'), )) abstol = 2 * lamch('s') if a1.dtype.char in 'GFD': bevx, = get_lapack_funcs(('hbevx', ), (a1, )) internal_name = 'hbevx' else: # a1.dtype.char in 'gfd' bevx, = get_lapack_funcs(('sbevx', ), (a1, )) internal_name = 'sbevx' # il+1, iu+1: translate python indexing (0 ... N-1) into Fortran # indexing (1 ... N) w, v, m, ifail, info = bevx(a1, vl, vu, il + 1, iu + 1, compute_v=not eigvals_only, mmax=max_ev, range=select, lower=lower, overwrite_ab=overwrite_a_band, abstol=abstol) # crop off w and v w = w[:m] if not eigvals_only: v = v[:, :m] if info < 0: raise ValueError('illegal value in %d-th argument of internal %s' % (-info, internal_name)) if info > 0: raise LinAlgError("eig algorithm did not converge") if eigvals_only: return w return w, v
def kmeans(obs, k_or_guess, iter=20, thresh=1e-5, check_finite=True): """ Performs k-means on a set of observation vectors forming k clusters. The k-means algorithm adjusts the classification of the observations into clusters and updates the cluster centroids until the position of the centroids is stable over successive iterations. In this implementation of the algorithm, the stability of the centroids is determined by comparing the absolute value of the change in the average Euclidean distance between the observations and their corresponding centroids against a threshold. This yields a code book mapping centroids to codes and vice versa. Parameters ---------- obs : ndarray Each row of the M by N array is an observation vector. The columns are the features seen during each observation. The features must be whitened first with the `whiten` function. k_or_guess : int or ndarray The number of centroids to generate. A code is assigned to each centroid, which is also the row index of the centroid in the code_book matrix generated. The initial k centroids are chosen by randomly selecting observations from the observation matrix. Alternatively, passing a k by N array specifies the initial k centroids. iter : int, optional The number of times to run k-means, returning the codebook with the lowest distortion. This argument is ignored if initial centroids are specified with an array for the ``k_or_guess`` parameter. This parameter does not represent the number of iterations of the k-means algorithm. thresh : float, optional Terminates the k-means algorithm if the change in distortion since the last k-means iteration is less than or equal to threshold. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- codebook : ndarray A k by N array of k centroids. The ith centroid codebook[i] is represented with the code i. The centroids and codes generated represent the lowest distortion seen, not necessarily the globally minimal distortion. distortion : float The mean (non-squared) Euclidean distance between the observations passed and the centroids generated. Note the difference to the standard definition of distortion in the context of the k-means algorithm, which is the sum of the squared distances. See Also -------- kmeans2 : a different implementation of k-means clustering with more methods for generating initial centroids but without using a distortion change threshold as a stopping criterion. whiten : must be called prior to passing an observation matrix to kmeans. Examples -------- >>> from numpy import array >>> from scipy.cluster.vq import vq, kmeans, whiten >>> import matplotlib.pyplot as plt >>> features = array([[ 1.9,2.3], ... [ 1.5,2.5], ... [ 0.8,0.6], ... [ 0.4,1.8], ... [ 0.1,0.1], ... [ 0.2,1.8], ... [ 2.0,0.5], ... [ 0.3,1.5], ... [ 1.0,1.0]]) >>> whitened = whiten(features) >>> book = np.array((whitened[0],whitened[2])) >>> kmeans(whitened,book) (array([[ 2.3110306 , 2.86287398], # random [ 0.93218041, 1.24398691]]), 0.85684700941625547) >>> from numpy import random >>> random.seed((1000,2000)) >>> codes = 3 >>> kmeans(whitened,codes) (array([[ 2.3110306 , 2.86287398], # random [ 1.32544402, 0.65607529], [ 0.40782893, 2.02786907]]), 0.5196582527686241) >>> # Create 50 datapoints in two clusters a and b >>> pts = 50 >>> a = np.random.multivariate_normal([0, 0], [[4, 1], [1, 4]], size=pts) >>> b = np.random.multivariate_normal([30, 10], ... [[10, 2], [2, 1]], ... size=pts) >>> features = np.concatenate((a, b)) >>> # Whiten data >>> whitened = whiten(features) >>> # Find 2 clusters in the data >>> codebook, distortion = kmeans(whitened, 2) >>> # Plot whitened data and cluster centers in red >>> plt.scatter(whitened[:, 0], whitened[:, 1]) >>> plt.scatter(codebook[:, 0], codebook[:, 1], c='r') >>> plt.show() """ obs = _asarray_validated(obs, check_finite=check_finite) if iter < 1: raise ValueError("iter must be at least 1, got %s" % iter) # Determine whether a count (scalar) or an initial guess (array) was passed. if not np.isscalar(k_or_guess): guess = _asarray_validated(k_or_guess, check_finite=check_finite) if guess.size < 1: raise ValueError("Asked for 0 clusters. Initial book was %s" % guess) return _kmeans(obs, guess, thresh=thresh) # k_or_guess is a scalar, now verify that it's an integer k = int(k_or_guess) if k != k_or_guess: raise ValueError("If k_or_guess is a scalar, it must be an integer.") if k < 1: raise ValueError("Asked for %d clusters." % k) # initialize best distance value to a large value best_dist = np.inf for i in range(iter): # the initial code book is randomly selected from observations guess = _kpoints(obs, k) book, dist = _kmeans(obs, guess, thresh=thresh) if dist < best_dist: best_book = book best_dist = dist return best_book, best_dist
def eig_banded(a_band, lower=False, eigvals_only=False, overwrite_a_band=False, select='a', select_range=None, max_ev=0, check_finite=True): """ Solve real symmetric or complex hermitian band matrix eigenvalue problem. Find eigenvalues w and optionally right eigenvectors v of a:: a v[:,i] = w[i] v[:,i] v.H v = identity The matrix a is stored in a_band either in lower diagonal or upper diagonal ordered form: a_band[u + i - j, j] == a[i,j] (if upper form; i <= j) a_band[ i - j, j] == a[i,j] (if lower form; i >= j) where u is the number of bands above the diagonal. Example of a_band (shape of a is (6,6), u=2):: upper form: * * a02 a13 a24 a35 * a01 a12 a23 a34 a45 a00 a11 a22 a33 a44 a55 lower form: a00 a11 a22 a33 a44 a55 a10 a21 a32 a43 a54 * a20 a31 a42 a53 * * Cells marked with * are not used. Parameters ---------- a_band : (u+1, M) array_like The bands of the M by M matrix a. lower : bool, optional Is the matrix in the lower form. (Default is upper form) eigvals_only : bool, optional Compute only the eigenvalues and no eigenvectors. (Default: calculate also eigenvectors) overwrite_a_band : bool, optional Discard data in a_band (may enhance performance) select : {'a', 'v', 'i'}, optional Which eigenvalues to calculate ====== ======================================== select calculated ====== ======================================== 'a' All eigenvalues 'v' Eigenvalues in the interval (min, max] 'i' Eigenvalues with indices min <= i <= max ====== ======================================== select_range : (min, max), optional Range of selected eigenvalues max_ev : int, optional For select=='v', maximum number of eigenvalues expected. For other values of select, has no meaning. In doubt, leave this parameter untouched. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- w : (M,) ndarray The eigenvalues, in ascending order, each repeated according to its multiplicity. v : (M, M) float or complex ndarray The normalized eigenvector corresponding to the eigenvalue w[i] is the column v[:,i]. Raises ------ LinAlgError If eigenvalue computation does not converge. See Also -------- eigvals_banded : eigenvalues for symmetric/Hermitian band matrices eig : eigenvalues and right eigenvectors of general arrays. eigh : eigenvalues and right eigenvectors for symmetric/Hermitian arrays eigh_tridiagonal : eigenvalues and right eiegenvectors for symmetric/Hermitian tridiagonal matrices Examples -------- >>> from scipy.linalg import eig_banded >>> A = np.array([[1, 5, 2, 0], [5, 2, 5, 2], [2, 5, 3, 5], [0, 2, 5, 4]]) >>> Ab = np.array([[1, 2, 3, 4], [5, 5, 5, 0], [2, 2, 0, 0]]) >>> w, v = eig_banded(Ab, lower=True) >>> np.allclose(A @ v - v @ np.diag(w), np.zeros((4, 4))) True >>> w = eig_banded(Ab, lower=True, eigvals_only=True) >>> w array([-4.26200532, -2.22987175, 3.95222349, 12.53965359]) Request only the eigenvalues between ``[-3, 4]`` >>> w, v = eig_banded(Ab, lower=True, select='v', select_range=[-3, 4]) >>> w array([-2.22987175, 3.95222349]) """ if eigvals_only or overwrite_a_band: a1 = _asarray_validated(a_band, check_finite=check_finite) overwrite_a_band = overwrite_a_band or (_datacopied(a1, a_band)) else: a1 = array(a_band) if issubclass(a1.dtype.type, inexact) and not isfinite(a1).all(): raise ValueError("array must not contain infs or NaNs") overwrite_a_band = 1 if len(a1.shape) != 2: raise ValueError('expected two-dimensional array') select, vl, vu, il, iu, max_ev = _check_select( select, select_range, max_ev, a1.shape[1]) del select_range if select == 0: if a1.dtype.char in 'GFD': # FIXME: implement this somewhen, for now go with builtin values # FIXME: calc optimal lwork by calling ?hbevd(lwork=-1) # or by using calc_lwork.f ??? # lwork = calc_lwork.hbevd(bevd.typecode, a1.shape[0], lower) internal_name = 'hbevd' else: # a1.dtype.char in 'fd': # FIXME: implement this somewhen, for now go with builtin values # see above # lwork = calc_lwork.sbevd(bevd.typecode, a1.shape[0], lower) internal_name = 'sbevd' bevd, = get_lapack_funcs((internal_name,), (a1,)) w, v, info = bevd(a1, compute_v=not eigvals_only, lower=lower, overwrite_ab=overwrite_a_band) else: # select in [1, 2] if eigvals_only: max_ev = 1 # calculate optimal abstol for dsbevx (see manpage) if a1.dtype.char in 'fF': # single precision lamch, = get_lapack_funcs(('lamch',), (array(0, dtype='f'),)) else: lamch, = get_lapack_funcs(('lamch',), (array(0, dtype='d'),)) abstol = 2 * lamch('s') if a1.dtype.char in 'GFD': internal_name = 'hbevx' else: # a1.dtype.char in 'gfd' internal_name = 'sbevx' bevx, = get_lapack_funcs((internal_name,), (a1,)) w, v, m, ifail, info = bevx( a1, vl, vu, il, iu, compute_v=not eigvals_only, mmax=max_ev, range=select, lower=lower, overwrite_ab=overwrite_a_band, abstol=abstol) # crop off w and v w = w[:m] if not eigvals_only: v = v[:, :m] _check_info(info, internal_name) if eigvals_only: return w return w, v
def logsumexp(a, axis=None, b=None, keepdims=False, return_sign=False): """Compute the log of the sum of exponentials of input elements. Parameters ---------- a : array_like Input array. axis : None or int or tuple of ints, optional Axis or axes over which the sum is taken. By default `axis` is None, and all elements are summed. .. versionadded:: 0.11.0 keepdims : bool, optional If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original array. .. versionadded:: 0.15.0 b : array-like, optional Scaling factor for exp(`a`) must be of the same shape as `a` or broadcastable to `a`. These values may be negative in order to implement subtraction. .. versionadded:: 0.12.0 return_sign : bool, optional If this is set to True, the result will be a pair containing sign information; if False, results that are negative will be returned as NaN. Default is False (no sign information). .. versionadded:: 0.16.0 Returns ------- res : ndarray The result, ``np.log(np.sum(np.exp(a)))`` calculated in a numerically more stable way. If `b` is given then ``np.log(np.sum(b*np.exp(a)))`` is returned. sgn : ndarray If return_sign is True, this will be an array of floating-point numbers matching res and +1, 0, or -1 depending on the sign of the result. If False, only one result is returned. See Also -------- numpy.logaddexp, numpy.logaddexp2 Notes ----- Numpy has a logaddexp function which is very similar to `logsumexp`, but only handles two arguments. `logaddexp.reduce` is similar to this function, but may be less stable. Examples -------- >>> from scipy.special import logsumexp >>> a = np.arange(10) >>> np.log(np.sum(np.exp(a))) 9.4586297444267107 >>> logsumexp(a) 9.4586297444267107 With weights >>> a = np.arange(10) >>> b = np.arange(10, 0, -1) >>> logsumexp(a, b=b) 9.9170178533034665 >>> np.log(np.sum(b*np.exp(a))) 9.9170178533034647 Returning a sign flag >>> logsumexp([1,2],b=[1,-1],return_sign=True) (1.5413248546129181, -1.0) Notice that `logsumexp` does not directly support masked arrays. To use it on a masked array, convert the mask into zero weights: >>> a = np.ma.array([np.log(2), 2, np.log(3)], ... mask=[False, True, False]) >>> b = (~a.mask).astype(int) >>> logsumexp(a.data, b=b), np.log(5) 1.6094379124341005, 1.6094379124341005 """ a = _asarray_validated(a, check_finite=False) if b is not None: a, b = np.broadcast_arrays(a, b) if np.any(b == 0): a = a + 0. # promote to at least float a[b == 0] = -np.inf a_max = np.amax(a, axis=axis, keepdims=True) if a_max.ndim > 0: a_max[~np.isfinite(a_max)] = 0 elif not np.isfinite(a_max): a_max = 0 if b is not None: b = np.asarray(b) tmp = b * np.exp(a - a_max) else: tmp = np.exp(a - a_max) # suppress warnings about log of zero with np.errstate(divide='ignore'): s = np.sum(tmp, axis=axis, keepdims=keepdims) if return_sign: sgn = np.sign(s) s *= sgn # /= makes more sense but we need zero -> zero out = np.log(s) if not keepdims: a_max = np.squeeze(a_max, axis=axis) out += a_max if return_sign: return out, sgn else: return out
def log_softmax(x, axis=None): r"""Compute the logarithm of the softmax function. In principle:: log_softmax(x) = log(softmax(x)) but using a more accurate implementation. Parameters ---------- x : array_like Input array. axis : int or tuple of ints, optional Axis to compute values along. Default is None and softmax will be computed over the entire array `x`. Returns ------- s : ndarray or scalar An array with the same shape as `x`. Exponential of the result will sum to 1 along the specified axis. If `x` is a scalar, a scalar is returned. Notes ----- `log_softmax` is more accurate than ``np.log(softmax(x))`` with inputs that make `softmax` saturate (see examples below). .. versionadded:: 1.5.0 Examples -------- >>> from scipy.special import log_softmax >>> from scipy.special import softmax >>> np.set_printoptions(precision=5) >>> x = np.array([1000.0, 1.0]) >>> y = log_softmax(x) >>> y array([ 0., -999.]) >>> with np.errstate(divide='ignore'): ... y = np.log(softmax(x)) ... >>> y array([ 0., -inf]) """ x = _asarray_validated(x, check_finite=False) x_max = np.amax(x, axis=axis, keepdims=True) if x_max.ndim > 0: x_max[~np.isfinite(x_max)] = 0 elif not np.isfinite(x_max): x_max = 0 tmp = x - x_max exp_tmp = np.exp(tmp) # suppress warnings about log of zero with np.errstate(divide='ignore'): s = np.sum(exp_tmp, axis=axis, keepdims=True) out = np.log(s) out = tmp - out return out
def sqrtm(A, disp=True, blocksize=64): """ Matrix square root. Parameters ---------- A : (N, N) array_like Matrix whose square root to evaluate disp : bool, optional Print warning if error in the result is estimated large instead of returning estimated error. (Default: True) blocksize : integer, optional If the blocksize is not degenerate with respect to the size of the input array, then use a blocked algorithm. (Default: 64) Returns ------- sqrtm : (N, N) ndarray Value of the sqrt function at `A` errest : float (if disp == False) Frobenius norm of the estimated error, ||err||_F / ||A||_F References ---------- .. [1] Edvin Deadman, Nicholas J. Higham, Rui Ralha (2013) "Blocked Schur Algorithms for Computing the Matrix Square Root, Lecture Notes in Computer Science, 7782. pp. 171-182. Examples -------- >>> from scipy.linalg import sqrtm >>> a = np.array([[1.0, 3.0], [1.0, 4.0]]) >>> r = sqrtm(a) >>> r array([[ 0.75592895, 1.13389342], [ 0.37796447, 1.88982237]]) >>> r.dot(r) array([[ 1., 3.], [ 1., 4.]]) """ A = _asarray_validated(A, check_finite=True, as_inexact=True) if len(A.shape) != 2: raise ValueError("Non-matrix input to matrix function.") if blocksize < 1: raise ValueError("The blocksize should be at least 1.") keep_it_real = np.isrealobj(A) if keep_it_real: T, Z = schur(A) if not np.array_equal(T, np.triu(T)): T, Z = rsf2csf(T, Z) else: T, Z = schur(A, output='complex') failflag = False try: R = _sqrtm_triu(T, blocksize=blocksize) ZH = np.conjugate(Z).T X = Z.dot(R).dot(ZH) except SqrtmError: failflag = True X = np.empty_like(A) X.fill(np.nan) if disp: if failflag: print("Failed to find a square root.") return X else: try: arg2 = norm(X.dot(X) - A, 'fro')**2 / norm(A, 'fro') except ValueError: # NaNs in matrix arg2 = np.inf return X, arg2
def kmeans(obs, k_or_guess, iter=20, thresh=1e-5, check_finite=True): """ Performs k-means on a set of observation vectors forming k clusters. The k-means algorithm adjusts the classification of the observations into clusters and updates the cluster centroids until the position of the centroids is stable over successive iterations. In this implementation of the algorithm, the stability of the centroids is determined by comparing the absolute value of the change in the average Euclidean distance between the observations and their corresponding centroids against a threshold. This yields a code book mapping centroids to codes and vice versa. Parameters ---------- obs : ndarray Each row of the M by N array is an observation vector. The columns are the features seen during each observation. The features must be whitened first with the `whiten` function. k_or_guess : int or ndarray The number of centroids to generate. A code is assigned to each centroid, which is also the row index of the centroid in the code_book matrix generated. The initial k centroids are chosen by randomly selecting observations from the observation matrix. Alternatively, passing a k by N array specifies the initial k centroids. iter : int, optional The number of times to run k-means, returning the codebook with the lowest distortion. This argument is ignored if initial centroids are specified with an array for the ``k_or_guess`` parameter. This parameter does not represent the number of iterations of the k-means algorithm. thresh : float, optional Terminates the k-means algorithm if the change in distortion since the last k-means iteration is less than or equal to thresh. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- codebook : ndarray A k by N array of k centroids. The i'th centroid codebook[i] is represented with the code i. The centroids and codes generated represent the lowest distortion seen, not necessarily the globally minimal distortion. distortion : float The mean (non-squared) Euclidean distance between the observations passed and the centroids generated. Note the difference to the standard definition of distortion in the context of the K-means algorithm, which is the sum of the squared distances. See Also -------- kmeans2 : a different implementation of k-means clustering with more methods for generating initial centroids but without using a distortion change threshold as a stopping criterion. whiten : must be called prior to passing an observation matrix to kmeans. Examples -------- >>> from numpy import array >>> from scipy.cluster.vq import vq, kmeans, whiten >>> import matplotlib.pyplot as plt >>> features = array([[ 1.9,2.3], ... [ 1.5,2.5], ... [ 0.8,0.6], ... [ 0.4,1.8], ... [ 0.1,0.1], ... [ 0.2,1.8], ... [ 2.0,0.5], ... [ 0.3,1.5], ... [ 1.0,1.0]]) >>> whitened = whiten(features) >>> book = np.array((whitened[0],whitened[2])) >>> kmeans(whitened,book) (array([[ 2.3110306 , 2.86287398], # random [ 0.93218041, 1.24398691]]), 0.85684700941625547) >>> from numpy import random >>> random.seed((1000,2000)) >>> codes = 3 >>> kmeans(whitened,codes) (array([[ 2.3110306 , 2.86287398], # random [ 1.32544402, 0.65607529], [ 0.40782893, 2.02786907]]), 0.5196582527686241) >>> # Create 50 datapoints in two clusters a and b >>> pts = 50 >>> a = np.random.multivariate_normal([0, 0], [[4, 1], [1, 4]], size=pts) >>> b = np.random.multivariate_normal([30, 10], ... [[10, 2], [2, 1]], ... size=pts) >>> features = np.concatenate((a, b)) >>> # Whiten data >>> whitened = whiten(features) >>> # Find 2 clusters in the data >>> codebook, distortion = kmeans(whitened, 2) >>> # Plot whitened data and cluster centers in red >>> plt.scatter(whitened[:, 0], whitened[:, 1]) >>> plt.scatter(codebook[:, 0], codebook[:, 1], c='r') >>> plt.show() """ obs = _asarray_validated(obs, check_finite=check_finite) if iter < 1: raise ValueError("iter must be at least 1, got %s" % iter) # Determine whether a count (scalar) or an initial guess (array) was passed. if not np.isscalar(k_or_guess): guess = _asarray_validated(k_or_guess, check_finite=check_finite) if guess.size < 1: raise ValueError("Asked for 0 clusters. Initial book was %s" % guess) return _kmeans(obs, guess, thresh=thresh) # k_or_guess is a scalar, now verify that it's an integer k = int(k_or_guess) if k != k_or_guess: raise ValueError("If k_or_guess is a scalar, it must be an integer.") if k < 1: raise ValueError("Asked for %d clusters." % k) # initialize best distance value to a large value best_dist = np.inf for i in xrange(iter): # the initial code book is randomly selected from observations guess = _kpoints(obs, k) book, dist = _kmeans(obs, guess, thresh=thresh) if dist < best_dist: best_book = book best_dist = dist return best_book, best_dist
def kmeans(obs, k_or_guess, iter=20, thresh=1e-5, check_finite=True): """ Performs k-means on a set of observation vectors forming k clusters. The k-means algorithm adjusts the centroids until sufficient progress cannot be made, i.e. the change in distortion since the last iteration is less than some threshold. This yields a code book mapping centroids to codes and vice versa. Distortion is defined as the sum of the squared differences between the observations and the corresponding centroid. Parameters ---------- obs : ndarray Each row of the M by N array is an observation vector. The columns are the features seen during each observation. The features must be whitened first with the `whiten` function. k_or_guess : int or ndarray The number of centroids to generate. A code is assigned to each centroid, which is also the row index of the centroid in the code_book matrix generated. The initial k centroids are chosen by randomly selecting observations from the observation matrix. Alternatively, passing a k by N array specifies the initial k centroids. iter : int, optional The number of times to run k-means, returning the codebook with the lowest distortion. This argument is ignored if initial centroids are specified with an array for the ``k_or_guess`` parameter. This parameter does not represent the number of iterations of the k-means algorithm. thresh : float, optional Terminates the k-means algorithm if the change in distortion since the last k-means iteration is less than or equal to thresh. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- codebook : ndarray A k by N array of k centroids. The i'th centroid codebook[i] is represented with the code i. The centroids and codes generated represent the lowest distortion seen, not necessarily the globally minimal distortion. distortion : float The distortion between the observations passed and the centroids generated. See Also -------- kmeans2 : a different implementation of k-means clustering with more methods for generating initial centroids but without using a distortion change threshold as a stopping criterion. whiten : must be called prior to passing an observation matrix to kmeans. Examples -------- >>> from numpy import array >>> from scipy.cluster.vq import vq, kmeans, whiten >>> features = array([[ 1.9,2.3], ... [ 1.5,2.5], ... [ 0.8,0.6], ... [ 0.4,1.8], ... [ 0.1,0.1], ... [ 0.2,1.8], ... [ 2.0,0.5], ... [ 0.3,1.5], ... [ 1.0,1.0]]) >>> whitened = whiten(features) >>> book = array((whitened[0],whitened[2])) >>> kmeans(whitened,book) (array([[ 2.3110306 , 2.86287398], # random [ 0.93218041, 1.24398691]]), 0.85684700941625547) >>> from numpy import random >>> random.seed((1000,2000)) >>> codes = 3 >>> kmeans(whitened,codes) (array([[ 2.3110306 , 2.86287398], # random [ 1.32544402, 0.65607529], [ 0.40782893, 2.02786907]]), 0.5196582527686241) """ obs = _asarray_validated(obs, check_finite=check_finite) if int(iter) < 1: raise ValueError('iter must be at least 1.') # Determine whether a count (scalar) or an initial guess (array) was passed. k = None guess = None try: k = int(k_or_guess) except TypeError: guess = _asarray_validated(k_or_guess, check_finite=check_finite) if guess is not None: if guess.size < 1: raise ValueError("Asked for 0 cluster ? initial book was %s" % guess) result = _kmeans(obs, guess, thresh=thresh) else: if k != k_or_guess: raise ValueError( 'if k_or_guess is a scalar, it must be an integer') # initialize best distance value to a large value best_dist = np.inf No = obs.shape[0] k = k_or_guess if k < 1: raise ValueError("Asked for 0 cluster ? ") for i in range(iter): # the initial code book is randomly selected from observations guess = take(obs, randint(0, No, k), 0) book, dist = _kmeans(obs, guess, thresh=thresh) if dist < best_dist: best_book = book best_dist = dist result = best_book, best_dist return result
def kmeans2(data, k, iter=10, thresh=1e-5, minit='random', missing='warn', check_finite=True): """ Classify a set of observations into k clusters using the k-means algorithm. The algorithm attempts to minimize the Euclidian distance between observations and centroids. Several initialization methods are included. Parameters ---------- data : ndarray A 'M' by 'N' array of 'M' observations in 'N' dimensions or a length 'M' array of 'M' one-dimensional observations. k : int or ndarray The number of clusters to form as well as the number of centroids to generate. If `minit` initialization string is 'matrix', or if a ndarray is given instead, it is interpreted as initial cluster to use instead. iter : int, optional Number of iterations of the k-means algrithm to run. Note that this differs in meaning from the iters parameter to the kmeans function. thresh : float, optional (not used yet) minit : str, optional Method for initialization. Available methods are 'random', 'points', and 'matrix': 'random': generate k centroids from a Gaussian with mean and variance estimated from the data. 'points': choose k observations (rows) at random from data for the initial centroids. 'matrix': interpret the k parameter as a k by M (or length k array for one-dimensional data) array of initial centroids. missing : str, optional Method to deal with empty clusters. Available methods are 'warn' and 'raise': 'warn': give a warning and continue. 'raise': raise an ClusterError and terminate the algorithm. check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Default: True Returns ------- centroid : ndarray A 'k' by 'N' array of centroids found at the last iteration of k-means. label : ndarray label[i] is the code or index of the centroid the i'th observation is closest to. """ data = _asarray_validated(data, check_finite=check_finite) if missing not in _valid_miss_meth: raise ValueError("Unkown missing method: %s" % str(missing)) # If data is rank 1, then we have 1 dimension problem. nd = np.ndim(data) if nd == 1: d = 1 # raise ValueError("Input of rank 1 not supported yet") elif nd == 2: d = data.shape[1] else: raise ValueError("Input of rank > 2 not supported") if np.size(data) < 1: raise ValueError("Input has 0 items.") # If k is not a single value, then it should be compatible with data's # shape if np.size(k) > 1 or minit == 'matrix': if not nd == np.ndim(k): raise ValueError("k is not an int and has not same rank than data") if d == 1: nc = len(k) else: (nc, dc) = k.shape if not dc == d: raise ValueError("k is not an int and has not same rank than\ data") clusters = k.copy() else: try: nc = int(k) except TypeError: raise ValueError("k (%s) could not be converted to an integer " % str(k)) if nc < 1: raise ValueError("kmeans2 for 0 clusters ? (k was %s)" % str(k)) if not nc == k: warnings.warn("k was not an integer, was converted.") try: init = _valid_init_meth[minit] except KeyError: raise ValueError("unknown init method %s" % str(minit)) clusters = init(data, k) if int(iter) < 1: raise ValueError( "iter = %s is not valid. iter must be a positive integer." % iter) return _kmeans2(data, clusters, iter, nc, _valid_miss_meth[missing])
def _prepare_x(self, x): """Reshape input x array to 1-D""" x = _asarray_validated(x, check_finite=False, as_inexact=True) x_shape = x.shape return x.ravel(), x_shape
def eigh_tridiagonal(d, e, eigvals_only=False, select='a', select_range=None, check_finite=True, tol=0., lapack_driver='auto'): """ Solve eigenvalue problem for a real symmetric tridiagonal matrix. Find eigenvalues `w` and optionally right eigenvectors `v` of ``a``:: a v[:,i] = w[i] v[:,i] v.H v = identity For a real symmetric matrix ``a`` with diagonal elements `d` and off-diagonal elements `e`. Parameters ---------- d : ndarray, shape (ndim,) The diagonal elements of the array. e : ndarray, shape (ndim-1,) The off-diagonal elements of the array. select : {'a', 'v', 'i'}, optional Which eigenvalues to calculate ====== ======================================== select calculated ====== ======================================== 'a' All eigenvalues 'v' Eigenvalues in the interval (min, max] 'i' Eigenvalues with indices min <= i <= max ====== ======================================== select_range : (min, max), optional Range of selected eigenvalues check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. tol : float The absolute tolerance to which each eigenvalue is required (only used when 'stebz' is the `lapack_driver`). An eigenvalue (or cluster) is considered to have converged if it lies in an interval of this width. If <= 0. (default), the value ``eps*|a|`` is used where eps is the machine precision, and ``|a|`` is the 1-norm of the matrix ``a``. lapack_driver : str LAPACK function to use, can be 'auto', 'stemr', 'stebz', 'sterf', or 'stev'. When 'auto' (default), it will use 'stemr' if ``select='a'`` and 'stebz' otherwise. When 'stebz' is used to find the eigenvalues and ``eigvals_only=False``, then a second LAPACK call (to ``?STEIN``) is used to find the corresponding eigenvectors. 'sterf' can only be used when ``eigvals_only=True`` and ``select='a'``. 'stev' can only be used when ``select='a'``. Returns ------- w : (M,) ndarray The eigenvalues, in ascending order, each repeated according to its multiplicity. v : (M, M) ndarray The normalized eigenvector corresponding to the eigenvalue ``w[i]`` is the column ``v[:,i]``. Raises ------ LinAlgError If eigenvalue computation does not converge. See Also -------- eigvalsh_tridiagonal : eigenvalues of symmetric/Hermitian tridiagonal matrices eig : eigenvalues and right eigenvectors for non-symmetric arrays eigh : eigenvalues and right eigenvectors for symmetric/Hermitian arrays eig_banded : eigenvalues and right eigenvectors for symmetric/Hermitian band matrices Notes ----- This function makes use of LAPACK ``S/DSTEMR`` routines. Examples -------- >>> from scipy.linalg import eigh_tridiagonal >>> d = 3*np.ones(4) >>> e = -1*np.ones(3) >>> w, v = eigh_tridiagonal(d, e) >>> A = np.diag(d) + np.diag(e, k=1) + np.diag(e, k=-1) >>> np.allclose(A @ v - v @ np.diag(w), np.zeros((4, 4))) True """ d = _asarray_validated(d, check_finite=check_finite) e = _asarray_validated(e, check_finite=check_finite) for check in (d, e): if check.ndim != 1: raise ValueError('expected one-dimensional array') if check.dtype.char in 'GFD': # complex raise TypeError('Only real arrays currently supported') if d.size != e.size + 1: raise ValueError('d (%s) must have one more element than e (%s)' % (d.size, e.size)) select, vl, vu, il, iu, _ = _check_select( select, select_range, 0, d.size) if not isinstance(lapack_driver, string_types): raise TypeError('lapack_driver must be str') drivers = ('auto', 'stemr', 'sterf', 'stebz', 'stev') if lapack_driver not in drivers: raise ValueError('lapack_driver must be one of %s, got %s' % (drivers, lapack_driver)) if lapack_driver == 'auto': lapack_driver = 'stemr' if select == 0 else 'stebz' func, = get_lapack_funcs((lapack_driver,), (d, e)) compute_v = not eigvals_only if lapack_driver == 'sterf': if select != 0: raise ValueError('sterf can only be used when select == "a"') if not eigvals_only: raise ValueError('sterf can only be used when eigvals_only is ' 'True') w, info = func(d, e) m = len(w) elif lapack_driver == 'stev': if select != 0: raise ValueError('stev can only be used when select == "a"') w, v, info = func(d, e, compute_v=compute_v) m = len(w) elif lapack_driver == 'stebz': tol = float(tol) internal_name = 'stebz' stebz, = get_lapack_funcs((internal_name,), (d, e)) # If getting eigenvectors, needs to be block-ordered (B) instead of # matirx-ordered (E), and we will reorder later order = 'E' if eigvals_only else 'B' m, w, iblock, isplit, info = stebz(d, e, select, vl, vu, il, iu, tol, order) else: # 'stemr' # ?STEMR annoyingly requires size N instead of N-1 e_ = empty(e.size+1, e.dtype) e_[:-1] = e stemr_lwork, = get_lapack_funcs(('stemr_lwork',), (d, e)) lwork, liwork, info = stemr_lwork(d, e_, select, vl, vu, il, iu, compute_v=compute_v) _check_info(info, 'stemr_lwork') m, w, v, info = func(d, e_, select, vl, vu, il, iu, compute_v=compute_v, lwork=lwork, liwork=liwork) _check_info(info, lapack_driver + ' (eigh_tridiagonal)') w = w[:m] if eigvals_only: return w else: # Do we still need to compute the eigenvalues? if lapack_driver == 'stebz': func, = get_lapack_funcs(('stein',), (d, e)) v, info = func(d, e, w, iblock, isplit) _check_info(info, 'stein (eigh_tridiagonal)', positive='%d eigenvectors failed to converge') # Convert block-order to matrix-order order = argsort(w) w, v = w[order], v[:, order] else: v = v[:, :m] return w, v
def eigh(a, b=None, lower=True, eigvals_only=False, overwrite_a=False, overwrite_b=False, turbo=True, eigvals=None, type=1, check_finite=True): """ Solve an ordinary or generalized eigenvalue problem for a complex Hermitian or real symmetric matrix. Find eigenvalues w and optionally eigenvectors v of matrix `a`, where `b` is positive definite:: a v[:,i] = w[i] b v[:,i] v[i,:].conj() a v[:,i] = w[i] v[i,:].conj() b v[:,i] = 1 Parameters ---------- a : (M, M) array_like A complex Hermitian or real symmetric matrix whose eigenvalues and eigenvectors will be computed. b : (M, M) array_like, optional A complex Hermitian or real symmetric definite positive matrix in. If omitted, identity matrix is assumed. lower : bool, optional Whether the pertinent array data is taken from the lower or upper triangle of `a`. (Default: lower) eigvals_only : bool, optional Whether to calculate only eigenvalues and no eigenvectors. (Default: both are calculated) turbo : bool, optional Use divide and conquer algorithm (faster but expensive in memory, only for generalized eigenvalue problem and if eigvals=None) eigvals : tuple (lo, hi), optional Indexes of the smallest and largest (in ascending order) eigenvalues and corresponding eigenvectors to be returned: 0 <= lo <= hi <= M-1. If omitted, all eigenvalues and eigenvectors are returned. type : int, optional Specifies the problem type to be solved: type = 1: a v[:,i] = w[i] b v[:,i] type = 2: a b v[:,i] = w[i] v[:,i] type = 3: b a v[:,i] = w[i] v[:,i] overwrite_a : bool, optional Whether to overwrite data in `a` (may improve performance) overwrite_b : bool, optional Whether to overwrite data in `b` (may improve performance) check_finite : bool, optional Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- w : (N,) float ndarray The N (1<=N<=M) selected eigenvalues, in ascending order, each repeated according to its multiplicity. v : (M, N) complex ndarray (if eigvals_only == False) The normalized selected eigenvector corresponding to the eigenvalue w[i] is the column v[:,i]. Normalization: type 1 and 3: v.conj() a v = w type 2: inv(v).conj() a inv(v) = w type = 1 or 2: v.conj() b v = I type = 3: v.conj() inv(b) v = I Raises ------ LinAlgError If eigenvalue computation does not converge, an error occurred, or b matrix is not definite positive. Note that if input matrices are not symmetric or hermitian, no error is reported but results will be wrong. See Also -------- eig : eigenvalues and right eigenvectors for non-symmetric arrays """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]: raise ValueError('expected square matrix') overwrite_a = overwrite_a or (_datacopied(a1, a)) if iscomplexobj(a1): cplx = True else: cplx = False if b is not None: b1 = _asarray_validated(b, check_finite=check_finite) overwrite_b = overwrite_b or _datacopied(b1, b) if len(b1.shape) != 2 or b1.shape[0] != b1.shape[1]: raise ValueError('expected square matrix') if b1.shape != a1.shape: raise ValueError("wrong b dimensions %s, should " "be %s" % (str(b1.shape), str(a1.shape))) if iscomplexobj(b1): cplx = True else: cplx = cplx or False else: b1 = None # Set job for fortran routines _job = (eigvals_only and 'N') or 'V' # port eigenvalue range from python to fortran convention if eigvals is not None: lo, hi = eigvals if lo < 0 or hi >= a1.shape[0]: raise ValueError('The eigenvalue range specified is not valid.\n' 'Valid range is [%s,%s]' % (0, a1.shape[0] - 1)) lo += 1 hi += 1 eigvals = (lo, hi) # set lower if lower: uplo = 'L' else: uplo = 'U' # fix prefix for lapack routines if cplx: pfx = 'he' else: pfx = 'sy' # Standard Eigenvalue Problem # Use '*evr' routines # FIXME: implement calculation of optimal lwork # for all lapack routines if b1 is None: (evr, ) = get_lapack_funcs((pfx + 'evr', ), (a1, )) if eigvals is None: w, v, info = evr(a1, uplo=uplo, jobz=_job, range="A", il=1, iu=a1.shape[0], overwrite_a=overwrite_a) else: (lo, hi) = eigvals w_tot, v, info = evr(a1, uplo=uplo, jobz=_job, range="I", il=lo, iu=hi, overwrite_a=overwrite_a) w = w_tot[0:hi - lo + 1] # Generalized Eigenvalue Problem else: # Use '*gvx' routines if range is specified if eigvals is not None: (gvx, ) = get_lapack_funcs((pfx + 'gvx', ), (a1, b1)) (lo, hi) = eigvals w_tot, v, ifail, info = gvx(a1, b1, uplo=uplo, iu=hi, itype=type, jobz=_job, il=lo, overwrite_a=overwrite_a, overwrite_b=overwrite_b) w = w_tot[0:hi - lo + 1] # Use '*gvd' routine if turbo is on and no eigvals are specified elif turbo: (gvd, ) = get_lapack_funcs((pfx + 'gvd', ), (a1, b1)) v, w, info = gvd(a1, b1, uplo=uplo, itype=type, jobz=_job, overwrite_a=overwrite_a, overwrite_b=overwrite_b) # Use '*gv' routine if turbo is off and no eigvals are specified else: (gv, ) = get_lapack_funcs((pfx + 'gv', ), (a1, b1)) v, w, info = gv(a1, b1, uplo=uplo, itype=type, jobz=_job, overwrite_a=overwrite_a, overwrite_b=overwrite_b) # Check if we had a successful exit if info == 0: if eigvals_only: return w else: return w, v elif info < 0: raise LinAlgError("illegal value in %i-th argument of internal" " fortran routine." % (-info)) elif info > 0 and b1 is None: raise LinAlgError("unrecoverable internal error.") # The algorithm failed to converge. elif 0 < info <= b1.shape[0]: if eigvals is not None: raise LinAlgError("the eigenvectors %s failed to" " converge." % nonzero(ifail) - 1) else: raise LinAlgError("internal fortran routine failed to converge: " "%i off-diagonal elements of an " "intermediate tridiagonal form did not converge" " to zero." % info) # This occurs when b is not positive definite else: raise LinAlgError("the leading minor of order %i" " of 'b' is not positive definite. The" " factorization of 'b' could not be completed" " and no eigenvalues or eigenvectors were" " computed." % (info - b1.shape[0]))
def hessenberg(a, calc_q=False, overwrite_a=False, check_finite=True): """ Compute Hessenberg form of a matrix. The Hessenberg decomposition is:: A = Q H Q^H where `Q` is unitary/orthogonal and `H` has only zero elements below the first sub-diagonal. Parameters ---------- a : (M, M) array_like Matrix to bring into Hessenberg form. calc_q : bool, optional Whether to compute the transformation matrix. Default is False. overwrite_a : bool, optional Whether to overwrite `a`; may improve performance. Default is False. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- H : (M, M) ndarray Hessenberg form of `a`. Q : (M, M) ndarray Unitary/orthogonal similarity transformation matrix ``A = Q H Q^H``. Only returned if ``calc_q=True``. """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2 or (a1.shape[0] != a1.shape[1]): raise ValueError('expected square matrix') overwrite_a = overwrite_a or (_datacopied(a1, a)) # if 2x2 or smaller: already in Hessenberg if a1.shape[0] <= 2: if calc_q: return a1, numpy.eye(a1.shape[0]) return a1 gehrd, gebal, gehrd_lwork = get_lapack_funcs( ('gehrd', 'gebal', 'gehrd_lwork'), (a1, )) ba, lo, hi, pivscale, info = gebal(a1, permute=0, overwrite_a=overwrite_a) if info < 0: raise ValueError('illegal value in %d-th argument of internal gebal ' '(hessenberg)' % -info) n = len(a1) lwork = _compute_lwork(gehrd_lwork, ba.shape[0], lo=lo, hi=hi) hq, tau, info = gehrd(ba, lo=lo, hi=hi, lwork=lwork, overwrite_a=1) if info < 0: raise ValueError('illegal value in %d-th argument of internal gehrd ' '(hessenberg)' % -info) h = numpy.triu(hq, -1) if not calc_q: return h # use orghr/unghr to compute q orghr, orghr_lwork = get_lapack_funcs(('orghr', 'orghr_lwork'), (a1, )) lwork = _compute_lwork(orghr_lwork, n, lo=lo, hi=hi) q, info = orghr(a=hq, tau=tau, lo=lo, hi=hi, lwork=lwork, overwrite_a=1) if info < 0: raise ValueError('illegal value in %d-th argument of internal orghr ' '(hessenberg)' % -info) return h, q
def hessenberg(a, calc_q=False, overwrite_a=False, check_finite=True): """ Compute Hessenberg form of a matrix. The Hessenberg decomposition is:: A = Q H Q^H where `Q` is unitary/orthogonal and `H` has only zero elements below the first sub-diagonal. Parameters ---------- a : (M, M) array_like Matrix to bring into Hessenberg form. calc_q : bool, optional Whether to compute the transformation matrix. Default is False. overwrite_a : bool, optional Whether to overwrite `a`; may improve performance. Default is False. check_finite : bool, optional Whether to check that the input matrix contains only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs. Returns ------- H : (M, M) ndarray Hessenberg form of `a`. Q : (M, M) ndarray Unitary/orthogonal similarity transformation matrix ``A = Q H Q^H``. Only returned if ``calc_q=True``. Examples -------- >>> from scipy.linalg import hessenberg >>> A = np.array([[2, 5, 8, 7], [5, 2, 2, 8], [7, 5, 6, 6], [5, 4, 4, 8]]) >>> H, Q = hessenberg(A, calc_q=True) >>> H array([[ 2. , -11.65843866, 1.42005301, 0.25349066], [ -9.94987437, 14.53535354, -5.31022304, 2.43081618], [ 0. , -1.83299243, 0.38969961, -0.51527034], [ 0. , 0. , -3.83189513, 1.07494686]]) >>> np.allclose(Q @ H @ Q.conj().T - A, np.zeros((4, 4))) True """ a1 = _asarray_validated(a, check_finite=check_finite) if len(a1.shape) != 2 or (a1.shape[0] != a1.shape[1]): raise ValueError('expected square matrix') overwrite_a = overwrite_a or (_datacopied(a1, a)) # if 2x2 or smaller: already in Hessenberg if a1.shape[0] <= 2: if calc_q: return a1, numpy.eye(a1.shape[0]) return a1 gehrd, gebal, gehrd_lwork = get_lapack_funcs(('gehrd', 'gebal', 'gehrd_lwork'), (a1,)) ba, lo, hi, pivscale, info = gebal(a1, permute=0, overwrite_a=overwrite_a) _check_info(info, 'gebal (hessenberg)', positive=False) n = len(a1) lwork = _compute_lwork(gehrd_lwork, ba.shape[0], lo=lo, hi=hi) hq, tau, info = gehrd(ba, lo=lo, hi=hi, lwork=lwork, overwrite_a=1) _check_info(info, 'gehrd (hessenberg)', positive=False) h = numpy.triu(hq, -1) if not calc_q: return h # use orghr/unghr to compute q orghr, orghr_lwork = get_lapack_funcs(('orghr', 'orghr_lwork'), (a1,)) lwork = _compute_lwork(orghr_lwork, n, lo=lo, hi=hi) q, info = orghr(a=hq, tau=tau, lo=lo, hi=hi, lwork=lwork, overwrite_a=1) _check_info(info, 'orghr (hessenberg)', positive=False) return h, q