svds#
- scipy.sparse.linalg.svds(A, k=6, ncv=None, tol=0, which='LM', v0=None, maxiter=None, return_singular_vectors=True, solver='arpack', rng=None, опции=None, *, random_state=None)[источник]#
Частичное разложение по сингулярным числам разреженной матрицы.
Вычислить наибольшее или наименьшее k сингулярные значения и соответствующие сингулярные векторы разреженной матрицы A. Порядок, в котором возвращаются сингулярные значения, не гарантирован.
В описаниях ниже пусть
M, N = A.shape.- Параметры:
- Andarray, разреженная матрица или LinearOperator
Матрица для разложения с плавающей точкой числового типа данных.
- kint, по умолчанию: 6
Количество сингулярных значений и сингулярных векторов для вычисления. Должно удовлетворять
1 <= k <= kmax, гдеkmax=min(M, N)дляsolver='propack'иkmax=min(M, N) - 1в противном случае.- ncvint, необязательный
Когда
solver='arpack', это количество векторов Ланцоша, сгенерированных. См. ‘arpack’ для подробностей. Когдаsolver='lobpcg'илиsolver='propack', этот параметр игнорируется.- tolfloat, опционально
Допуск для сингулярных значений. Ноль (по умолчанию) означает машинную точность.
- which{‘LM’, ‘SM’}
Который k сингулярные значения для поиска: либо наибольшие по величине ('LM'), либо наименьшие по величине ('SM') сингулярные значения.
- v0ndarray, необязательно
Начальный вектор для итерации; см. документацию по конкретному методу (‘arpack’, 'lobpcg'), или ‘propack’ подробности.
- maxiterint, необязательный
Максимальное количество итераций; см. документацию по конкретному методу (‘arpack’, 'lobpcg'), или ‘propack’ подробности.
- return_singular_vectors{True, False, "u", "vh"}
Сингулярные значения всегда вычисляются и возвращаются; этот параметр управляет вычислением и возвратом сингулярных векторов.
True: возвращает сингулярные векторы.False: не возвращать сингулярные векторы."u": еслиM <= N, вычислить только левые сингулярные векторы и вернутьNoneдля правых сингулярных векторов. В противном случае вычислить все сингулярные векторы."vh": еслиM > N, вычислять только правые сингулярные векторы и возвращатьNoneдля левых сингулярных векторов. В противном случае вычислять все сингулярные векторы.
Если
solver='propack', опция учитывается независимо от формы матрицы.- solver{‘arpack’, ‘propack’, ‘lobpcg’}, опционально
Используемый решатель. ‘arpack’, 'lobpcg', и ‘propack’ поддерживаются. По умолчанию: ‘arpack’.
- rng{None, int,
numpy.random.Generator, опционально Если rng передается по ключевому слову, типы, отличные от
numpy.random.Generatorпередаются вnumpy.random.default_rngдля создания экземпляраGenerator. Если rng уже являетсяGeneratorэкземпляр, то предоставленный экземпляр используется. Укажите rng для повторяемого поведения функции.Если этот аргумент передаётся по позиции или random_state передается по ключевому слову, устаревшее поведение для аргумента random_state применяется:
Если random_state равно None (или
numpy.random),numpy.random.RandomStateиспользуется синглтон.Если random_state является int, новый
RandomStateиспользуется экземпляр, инициализированный с random_state.Если random_state уже является
GeneratorилиRandomStateэкземпляр, тогда этот экземпляр используется.
Изменено в версии 1.15.0: В рамках SPEC-007 переход от использования
numpy.random.RandomStatetonumpy.random.Generator, этот ключевое слово было изменено с random_state to rng. В переходный период оба ключевых слова будут продолжать работать, хотя только одно может быть указано за раз. После переходного периода вызовы функций, использующие random_state ключевое слово будет выдавать предупреждения. Поведение обоих random_state и rng описаны выше, но только rng ключевое слово должно использоваться в новом коде.- опцииdict, optional
Словарь опций, специфичных для решателя. В настоящее время опции, специфичные для решателя, не поддерживаются; этот параметр зарезервирован для будущего использования.
- Возвращает:
- undarray, shape=(M, k)
Унитарная матрица, имеющая левые сингулярные векторы в качестве столбцов.
- sndarray, shape=(k,)
Сингулярные значения.
- vhndarray, shape=(k, N)
Унитарная матрица, имеющая правые сингулярные векторы в качестве строк.
Примечания
Это наивная реализация, использующая ARPACK или LOBPCG в качестве решателя собственных значений матрицы
A.conj().T @ AилиA @ A.conj().T, в зависимости от того, какой размер меньше, с последующим методом Рэлея-Ритца как постобработкой; см. Использование нормальной матрицы, в методе Рэлея-Ритца, (2022, 19 ноя.), Википедия, https://w.wiki/4zms.В качестве альтернативы можно вызвать решатель PROPACK.
Варианты входной матрицы A числовой тип данных может быть ограничен. Только
solver="lobpcg"поддерживает все типы данных с плавающей точкой вещественные: ‘np.float32’, ‘np.float64’, ‘np.longdouble’ и комплексные: ‘np.complex64’, ‘np.complex128’, ‘np.clongdouble’.solver="arpack"поддерживает только ‘np.float32’, ‘np.float64’ и ‘np.complex128’.Примеры
Построить матрицу A из сингулярных значений и векторов.
>>> import numpy as np >>> from scipy import sparse, linalg, stats >>> from scipy.sparse.linalg import svds, aslinearoperator, LinearOperator
Построение плотной матрицы A из сингулярных значений и векторов.
>>> rng = np.random.default_rng() >>> orthogonal = stats.ortho_group.rvs(10, random_state=rng) >>> s = [1e-3, 1, 2, 3, 4] # non-zero singular values >>> u = orthogonal[:, :5] # left singular vectors >>> vT = orthogonal[:, 5:].T # right singular vectors >>> A = u @ np.diag(s) @ vT
Всего с четырьмя сингулярными значениями/векторами SVD аппроксимирует исходную матрицу.
>>> u4, s4, vT4 = svds(A, k=4) >>> A4 = u4 @ np.diag(s4) @ vT4 >>> np.allclose(A4, A, atol=1e-3) True
Со всеми пятью ненулевыми сингулярными значениями/векторами мы можем более точно воспроизвести исходную матрицу.
>>> u5, s5, vT5 = svds(A, k=5) >>> A5 = u5 @ np.diag(s5) @ vT5 >>> np.allclose(A5, A) True
Сингулярные значения соответствуют ожидаемым сингулярным значениям.
>>> np.allclose(s5, s) True
Поскольку сингулярные значения в этом примере не близки друг к другу, каждый сингулярный вектор совпадает, как и ожидалось, с точностью до знака.
>>> (np.allclose(np.abs(u5), np.abs(u)) and ... np.allclose(np.abs(vT5), np.abs(vT))) True
Сингулярные векторы также ортогональны.
>>> (np.allclose(u5.T @ u5, np.eye(5)) and ... np.allclose(vT5 @ vT5.T, np.eye(5))) True
Если существуют (почти) кратные сингулярные значения, соответствующие индивидуальные сингулярные векторы могут быть неустойчивыми, но всё инвариантное подпространство, содержащее все такие сингулярные векторы, вычисляется точно, что может быть измерено углами между подпространствами через 'subspace_angles'.
>>> rng = np.random.default_rng() >>> s = [1, 1 + 1e-6] # non-zero singular values >>> u, _ = np.linalg.qr(rng.standard_normal((99, 2))) >>> v, _ = np.linalg.qr(rng.standard_normal((99, 2))) >>> vT = v.T >>> A = u @ np.diag(s) @ vT >>> A = A.astype(np.float32) >>> u2, s2, vT2 = svds(A, k=2, rng=rng) >>> np.allclose(s2, s) True
Углы между отдельными точными и вычисленными сингулярными векторами могут быть не такими малыми. Для проверки используйте:
>>> (linalg.subspace_angles(u2[:, :1], u[:, :1]) + ... linalg.subspace_angles(u2[:, 1:], u[:, 1:])) array([0.06562513]) # may vary >>> (linalg.subspace_angles(vT2[:1, :].T, vT[:1, :].T) + ... linalg.subspace_angles(vT2[1:, :].T, vT[1:, :].T)) array([0.06562507]) # may vary
В отличие от углов между 2-мерными инвариантными подпространствами, которые охватывают эти векторы, которые малы для правых сингулярных векторов
>>> linalg.subspace_angles(u2, u).sum() < 1e-6 True
а также для левых сингулярных векторов.
>>> linalg.subspace_angles(vT2.T, vT.T).sum() < 1e-6 True
Следующий пример следует примеру ‘sklearn.decomposition.TruncatedSVD’.
>>> rng = np.random.default_rng() >>> X_dense = rng.random(size=(100, 100)) >>> X_dense[:, 2 * np.arange(50)] = 0 >>> X = sparse.csr_array(X_dense) >>> _, singular_values, _ = svds(X, k=5, rng=rng) >>> print(singular_values) [ 4.3221... 4.4043... 4.4907... 4.5858... 35.4549...]
Функция может быть вызвана без явного построения транспонирования входной матрицы.
>>> rng = np.random.default_rng() >>> G = sparse.random_array((8, 9), density=0.5, rng=rng) >>> Glo = aslinearoperator(G) >>> _, singular_values_svds, _ = svds(Glo, k=5, rng=rng) >>> _, singular_values_svd, _ = linalg.svd(G.toarray()) >>> np.allclose(singular_values_svds, singular_values_svd[-4::-1]) True
Наиболее эффективный по памяти сценарий - когда ни исходная матрица, ни её транспонированная версия не создаются явно. Наш пример вычисляет наименьшие сингулярные значения и векторы 'LinearOperator', созданного из функции numpy 'np.diff', используемой построчно для соответствия работе 'LinearOperator' со столбцами.
>>> diff0 = lambda a: np.diff(a, axis=0)
Давайте создадим матрицу из 'diff0' для использования только для проверки.
>>> n = 5 # The dimension of the space. >>> M_from_diff0 = diff0(np.eye(n)) >>> print(M_from_diff0.astype(int)) [[-1 1 0 0 0] [ 0 -1 1 0 0] [ 0 0 -1 1 0] [ 0 0 0 -1 1]]
Матрица ‘M_from_diff0’ является двудиагональной и может быть альтернативно создана напрямую с помощью
>>> M = - np.eye(n - 1, n, dtype=int) >>> np.fill_diagonal(M[:,1:], 1) >>> np.allclose(M, M_from_diff0) True
Его транспонирование
>>> print(M.T) [[-1 0 0 0] [ 1 -1 0 0] [ 0 1 -1 0] [ 0 0 1 -1] [ 0 0 0 1]]
может рассматриваться как матрица инцидентности; см. Матрица инцидентности, (2022, 19 ноя.), Википедия, https://w.wiki/5YXU, линейного графа с 5 вершинами и 4 рёбрами. Нормальная матрица 5x5
M.T @ Mследовательно, является>>> print(M.T @ M) [[ 1 -1 0 0 0] [-1 2 -1 0 0] [ 0 -1 2 -1 0] [ 0 0 -1 2 -1] [ 0 0 0 -1 1]]
графовый лапласиан, тогда как фактически используемая в 'svds' матрица нормального размера 4x4
M @ M.T>>> print(M @ M.T) [[ 2 -1 0 0] [-1 2 -1 0] [ 0 -1 2 -1] [ 0 0 -1 2]]
является так называемым рёберным лапласианом; см. Симметричный лапласиан через матрицу инцидентности, в Лапласиан матрицы, (2022, 19 ноя.), Википедия, https://w.wiki/5YXW.
Настройка 'LinearOperator' требует опций 'rmatvec' и 'rmatmat' умножения на транспонированную матрицу
M.T, но мы хотим быть матрично-свободными для экономии памяти, поэтому зная, какM.Tвыглядит как, мы вручную конструируем следующую функцию для использования вrmatmat=diff0t.>>> def diff0t(a): ... if a.ndim == 1: ... a = a[:,np.newaxis] # Turn 1D into 2D array ... d = np.zeros((a.shape[0] + 1, a.shape[1]), dtype=a.dtype) ... d[0, :] = - a[0, :] ... d[1:-1, :] = a[0:-1, :] - a[1:, :] ... d[-1, :] = a[-1, :] ... return d
Мы проверяем, что наша функция 'diff0t' для транспонирования матрицы корректна.
>>> np.allclose(M.T, diff0t(np.eye(n-1))) True
Теперь мы настраиваем наш матрично-свободный ‘LinearOperator’ под названием ‘diff0_func_aslo’ и для проверки матричный ‘diff0_matrix_aslo’.
>>> def diff0_func_aslo_def(n): ... return LinearOperator(matvec=diff0, ... matmat=diff0, ... rmatvec=diff0t, ... rmatmat=diff0t, ... shape=(n - 1, n)) >>> diff0_func_aslo = diff0_func_aslo_def(n) >>> diff0_matrix_aslo = aslinearoperator(M_from_diff0)
И проверять как матрицу, так и её транспонирование в 'LinearOperator'.
>>> np.allclose(diff0_func_aslo(np.eye(n)), ... diff0_matrix_aslo(np.eye(n))) True >>> np.allclose(diff0_func_aslo.T(np.eye(n-1)), ... diff0_matrix_aslo.T(np.eye(n-1))) True
После проверки настройки 'LinearOperator', мы запускаем решатель.
>>> n = 100 >>> diff0_func_aslo = diff0_func_aslo_def(n) >>> u, s, vT = svds(diff0_func_aslo, k=3, which='SM')
Квадраты сингулярных чисел и сингулярные векторы известны явно; см. Чистые граничные условия Дирихле, в Собственные значения и собственные векторы второй производной, (2022, 19 ноября), Википедия, https://w.wiki/5YX6, поскольку ‘diff’ соответствует первой производной, и его матрица нормальных уравнений меньшего размера n-1 x n-1
M @ M.Tпредставляют дискретную вторую производную с граничными условиями Дирихле. Мы используем эти аналитические выражения для проверки.>>> se = 2. * np.sin(np.pi * np.arange(1, 4) / (2. * n)) >>> ue = np.sqrt(2 / n) * np.sin(np.pi * np.outer(np.arange(1, n), ... np.arange(1, 4)) / n) >>> np.allclose(s, se, atol=1e-3) True >>> np.allclose(np.abs(u), np.abs(ue), atol=1e-6) True