Подтвердить что ты не робот

Восстановление имен функций explain_variance_ratio_ в PCA с помощью sklearn

Я пытаюсь восстановить из PCA, сделанного с помощью scikit-learn, , которые выбираются как релевантные.

Классический пример с набором данных IRIS.

import pandas as pd
import pylab as pl
from sklearn import datasets
from sklearn.decomposition import PCA

# load dataset
iris = datasets.load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)

# normalize data
df_norm = (df - df.mean()) / df.std()

# PCA
pca = PCA(n_components=2)
pca.fit_transform(df_norm.values)
print pca.explained_variance_ratio_

Это возвращает

In [42]: pca.explained_variance_ratio_
Out[42]: array([ 0.72770452,  0.23030523])

Как я могу восстановить две функции, которые позволяют объяснить эти два объяснения в наборе данных? С другой стороны, как я могу получить индекс этих функций в iris.feature_names?

In [47]: print iris.feature_names
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

Заранее благодарим за помощь.

4b9b3361

Ответ 1

Эта информация включена в атрибут pca: components_. Как описано в документации, pca.components_ выводит массив [n_components, n_features], чтобы узнать, как компоненты линейно связаны с различными функциями, которые вы должны:

Примечание: каждый коэффициент представляет корреляцию между конкретной парой компонента и признака

import pandas as pd
import pylab as pl
from sklearn import datasets
from sklearn.decomposition import PCA

# load dataset
iris = datasets.load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)

# normalize data
from sklearn import preprocessing
data_scaled = pd.DataFrame(preprocessing.scale(df),columns = df.columns) 

# PCA
pca = PCA(n_components=2)
pca.fit_transform(data_scaled)

# Dump components relations with features:
print pd.DataFrame(pca.components_,columns=data_scaled.columns,index = ['PC-1','PC-2'])

      sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)
PC-1           0.522372         -0.263355           0.581254          0.565611
PC-2          -0.372318         -0.925556          -0.021095         -0.065416

ВАЖНО: В качестве дополнительного комментария обратите внимание, что знак PCA не влияет на его интерпретацию, поскольку знак не влияет на дисперсию, содержащуюся в каждом компоненте. Важны только относительные признаки признаков, формирующих измерение PCA. Фактически, если вы снова запустите код PCA, вы можете получить размеры PCA с инвертированными знаками. Для интуитивного представления об этом подумайте о векторе и его негативе в трехмерном пространстве - оба по существу представляют одно и то же направление в пространстве. Проверьте этот пост для дальнейшего использования.

Ответ 2

Изменить: как прокомментировали другие, вы можете получить те же значения из атрибута .components_.


Каждый главный компонент представляет собой линейную комбинацию исходных переменных:

pca-coef

где X_i - исходные переменные, а Beta_i - соответствующие веса или так называемые коэффициенты.

Чтобы получить вес, вы можете просто передать матрицу идентичности методу transform:

>>> i = np.identity(df.shape[1])  # identity matrix
>>> i
array([[ 1.,  0.,  0.,  0.],
       [ 0.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  1.]])

>>> coef = pca.transform(i)
>>> coef
array([[ 0.5224, -0.3723],
       [-0.2634, -0.9256],
       [ 0.5813, -0.0211],
       [ 0.5656, -0.0654]])

Каждый столбец вышеприведенной матрицы coef показывает веса в линейной комбинации, которая получает соответствующую главную составляющую:

>>> pd.DataFrame(coef, columns=['PC-1', 'PC-2'], index=df.columns)
                    PC-1   PC-2
sepal length (cm)  0.522 -0.372
sepal width (cm)  -0.263 -0.926
petal length (cm)  0.581 -0.021
petal width (cm)   0.566 -0.065

[4 rows x 2 columns]

Например, выше показано, что второй главный компонент (PC-2) в основном выравнивается с sepal width, который имеет самый высокий вес 0.926 по абсолютной величине;

Поскольку данные были нормализованы, вы можете подтвердить, что основные компоненты имеют дисперсию 1.0, которая эквивалентна каждому вектору коэффициентов, имеющему норму 1.0:

>>> np.linalg.norm(coef,axis=0)
array([ 1.,  1.])

Можно также подтвердить, что главные компоненты можно вычислить как точечное произведение вышеуказанных коэффициентов и исходных переменных:

>>> np.allclose(df_norm.values.dot(coef), pca.fit_transform(df_norm.values))
True

Обратите внимание, что нам нужно использовать numpy.allclose вместо обычного оператора равенства из-за ошибки точности с плавающей запятой.

Ответ 3

То, как этот вопрос сформулирован, напоминает мне о непонимании Принципиального Компонента, когда я впервые пытался понять это. Id нравится проходить через это здесь, надеясь, что другие не будут тратить столько времени на дорогу в никуда, как я делал, прежде чем пенни наконец упали.

Понятие "восстановления" имен функций предполагает, что PCA идентифицирует те функции, которые наиболее важны в наборе данных. Это не совсем верно.

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

Чтобы привести эту теорию в практические примеры кода примера @Rafas выше:

# load dataset
iris = datasets.load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)

# normalize data
from sklearn import preprocessing
data_scaled = pd.DataFrame(preprocessing.scale(df),columns = df.columns) 

# PCA
pca = PCA(n_components=2)
pca.fit_transform(data_scaled)

рассмотрим следующее:

post_pca_array = pca.fit_transform(data_scaled)

print data_scaled.shape
(150, 4)

print post_pca_array.shape
(150, 2)

В этом случае post_pca_array имеет те же 150 строк данных, что и data_scaled, но data_scaled четыре столбца сокращены с четырех до двух.

Критическая точка здесь состоит в том, что два столбца - или компоненты, которые должны быть терминологически согласованы - post_pca_array, не являются двумя "лучшими" столбцами data_scaled. Это два новых столбца, определяемые алгоритмом модуля sklearn.decomposition s PCA. Второй столбец PC-2 в примере @Rafas сообщается sepal_width больше, чем любой другой столбец, но значения в PC-2 и data_scaled['sepal_width'] не совпадают.

Таким образом, хотя интересно узнать, насколько каждый столбец исходных данных внес вклад в компоненты набора данных после ПКА, понятие "восстановления" имен столбцов мало вводит в заблуждение и, конечно, вводит меня в заблуждение в течение длительного времени время. Единственная ситуация, в которой было бы совпадение между пост-PCA и исходными столбцами, было бы, если бы количество основных компонентов было установлено с тем же номером, что и столбцы в оригинале. Однако не было бы смысла использовать одинаковое количество столбцов, потому что данные не изменились бы. Вы бы только пошли туда, чтобы вернуться, как это было.

Ответ 4

С учетом вашей установленной оценки pca компоненты должны быть найдены в pca.components_, которые представляют направления наибольшей дисперсии в наборе данных.

Ответ 5

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

Получить the most important feature name на ПК:

from sklearn.decomposition import PCA
import pandas as pd
import numpy as np
np.random.seed(0)

# 10 samples with 5 features
train_features = np.random.rand(10,5)

model = PCA(n_components=2).fit(train_features)
X_pc = model.transform(train_features)

# number of components
n_pcs= model.components_.shape[0]

# get the index of the most important feature on EACH component i.e. largest absolute value
# using LIST COMPREHENSION HERE
most_important = [np.abs(model.components_[i]).argmax() for i in range(n_pcs)]

initial_feature_names = ['a','b','c','d','e']

# get the names
most_important_names = [initial_feature_names[most_important[i]] for i in range(n_pcs)]

# using LIST COMPREHENSION HERE AGAIN
dic = {'PC{}'.format(i+1): most_important_names[i] for i in range(n_pcs)}

# build the dataframe
df = pd.DataFrame(sorted(dic.items()))

Это печатает:

     0  1
 0  PC1  e
 1  PC2  d

Заключение/Объяснение:

Таким образом, на ПК1 функция с именем e является наиболее важной, а на ПК2 - d.