Scraper Обновлено: 5 August, 2019

Пример декомпозиции сингулярного значения в Python

  Перевод   Ссылка на автора

Разложение по сингулярным значениям, или SVD, имеет широкий спектр применений. К ним относятся уменьшение размерности, сжатие изображения и шумоподавление данных. По сути, SVD утверждает, что матрица может быть представлена ​​как произведение трех других матриц. В математическом плане SVD можно записать следующим образом:

гдеNколичество строк (то есть выборок) иппредставляет количество измерений.

Предположим, у нас была матрица,

Для того, чтобы определить связанныйUматрица, мы должны сначала найти собственные векторы матрицыумножается на транспонирование матрицы,

поскольку

Напомним, как определяется определение собственных векторов и собственных значений:

Последнее также может быть выражено как:

Итак, возвращаясь к нашему примеру:

Мы получаем полином четвертой степени.

После решения мы заменим лямбду одним из собственных значений.

После умножения матрицы на векторИксполучаем следующее:

При решении уравнений получаем:

Мы подключаем собственные векторы в столбцыU,

Затем мы повторим тот же процесс для транспонирования матрицыумножается на матрицу,

После решения получим выражение дляВ,

В заключение,Sявляется диагональной матрицей, значения которой являются квадратным корнем из собственных значений либо

Здесь все становится интересно. Мы знаем, что произведение всех трех матриц эквивалентно матрице в левой части.

Мы можем исключить особенности и при этом сохранить аппроксимацию исходной матрицы. Скажи, что матрицаэто набор данных столбцов и строк или пикселей, которые составляют изображение, мы можем теоретически обучить модели, используя вновь сформированную матрицу, и достичь сопоставимой, если не лучшей (из-за проклятия размерности) точности.

Код

Давайте посмотрим, как мы можем применить декомпозицию Singular Value в Python. Для начала импортируйте следующие библиотеки.

import numpy as np
from sklearn.datasets import load_digits
from matplotlib import pyplot as plt
from sklearn.decomposition import TruncatedSVD
float_formatter = lambda x: "%.2f" % x
np.set_printoptions(formatter={'float_kind':float_formatter})
from sklearn.ensemble import RandomForestClassifier

В следующем уроке мы попытаемся классифицировать рукописные цифры. К счастью,scikit-learnБиблиотека предоставляет функцию-оболочку для импорта набора данных в нашу программу.

X, y = load_digits(return_X_y=True)

Набор данных содержит 1797 8x8 изображений. Если вы укажетеreturn_X_y=Trueфункция вернет пиксели в виде одномерного массива.

X.shape

Yсодержит метки для каждой цифры.

y

Давайте посмотрим на первую цифру. Как мы видим, это просто массив длиной 64, содержащий интенсивность пикселей.

image = X[0]

Если мы хотим просмотреть изображение с помощьюmatplotlib, мы должны сначала изменить массив.

image = image.reshape((8, 8))plt.matshow(image, cmap = 'gray')

Далее мы будем использовать разложение по сингулярным значениям, чтобы увидеть, сможем ли мы восстановить изображение, используя только 2 функции для каждой строки.sматрица, возвращаемая функцией, должна быть преобразована в диагональную матрицу с помощьюdiagметод. По умолчанию,diagсоздаст матрицу, котораян х нотносительно исходной матрицы. Это вызывает проблему, так как размер матриц больше не соответствует правилу умножения матриц, когда количество столбцов в матрице должно соответствовать количеству строк в другой матрице. Поэтому мы создаем новыйм х нматрица и заполнить первыйн х нчасть этого с диагональной матрицей.

U, s, V = np.linalg.svd(image)S = np.zeros((image.shape[0], image.shape[1]))S[:image.shape[0], :image.shape[0]] = np.diag(s)n_component = 2S = S[:, :n_component]
VT = VT[:n_component, :]A = U.dot(Sigma.dot(VT))print(A)
plt.matshow(A, cmap = 'gray')

Мы можем получить уменьшенное пространство признаков, взяв точечное произведениеUа такжеSматрицы.

U.dot(S)

Оригинал против уменьшенного пространства функций

Давайте сравним точность модели случайного леса, когда она обучается с использованием оригинальных рукописных цифр и когда она обучается с использованием уменьшенного пространства признаков, полученного из разложения по сингулярным значениям.

Мы можем измерить точность модели, взглянув на показатель Out-Of-Bag. Если вы не знакомы с концепцией OOB, я рекомендую вам оформить заказ это пост на Случайный Лес.

rf_original = RandomForestClassifier(oob_score=True)rf_original.fit(X, y)rf_original.oob_score_

Далее мы создаем и подгоняем экземплярTruncatedSVDкласс с 2 компонентами. Стоит отметить, что в отличие от предыдущего примера, мы используем функции 2/64.

svd = TruncatedSVD(n_components=2)X_reduced = svd.fit_transform(X)

Каждое изображение (то есть строка) в сокращенном наборе данных содержит 2 элемента.

X_reduced[0]

Взглянув на изображение, трудно различить, из какой цифры состоит изображение, вполне может быть 5, а не 0.

image_reduced = svd.inverse_transform(X_reduced[0].reshape(1,-1))image_reduced = image_reduced.reshape((8,8))plt.matshow(image_reduced, cmap = 'gray')

После обучения классификатора случайных лесов на сокращенном наборе данных мы получаем скудную точность 36,7%.

rf_reduced = RandomForestClassifier(oob_score=True)rf_reduced.fit(X_reduced, y)rf_reduced.oob_score_

Мы можем получить общую дисперсию, объясняя, взяв суммуexplained_variance_ratio_свойство. Как правило, мы хотим стремиться к 80-90 процентам.

svd.explained_variance_ratio_.sum()

Давайте попробуем еще раз, только на этот раз мы используем 16 компонентов. Мы проверяем количество информации, содержащейся в 16 функциях.

svd = TruncatedSVD(n_components=16)X_reduced = svd.fit_transform(X)svd.explained_variance_ratio_.sum()

Мы получаем точность, сопоставимую с моделью, обученной с использованием исходных изображений, и мы использовали 16/64 = 0,25 объем данных.

rf_reduced = RandomForestClassifier(oob_score=True)rf_reduced.fit(X_reduced, y)rf_reduced.oob_score_