Відновлення імен функцій объясненного_вариантного_соотношения_ в PCA за допомогою sklearn


78

Я намагаюся оговтатися від 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)']

Заздалегідь дякую за допомогу.


4
pca.components_це те, що ви шукаєте.
exAres 02

Якщо ви хочете отримати його single most important feature nameна певному ПК (або на всіх ПК), див. Мою відповідь у кінці цієї сторінки.
seralouk

Відповіді:


86

Ця інформація міститься в 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 із перевернутими знаками. Для інтуїції щодо цього подумайте про вектор та його негатив у тривимірному просторі - обидва вони по суті представляють один і той же напрямок у просторі. Перегляньте цю публікацію для подальшої довідки.


Компоненти насправді є комбінаціями ознак, тому будь-яка конкретна особливість (певною мірою) співвідноситься з різними компонентами ....
Рафа,

3
Тож скажіть, що ви хочете знати, яка оригінальна особливість була найважливішою, чи варто просто взяти абсолютні значення та підсумувати їх? Я маю на увазі, починаючи з останнього рядка відповіді: pd.DataFrame (pca.components_, columns = data_scaled.columns, index = ['PC-1', 'PC-2']). Abs (). Sum (вісь = 0), що призводить до значень: 0.894690 1.188911 0.602349 0.631027. Чи можна цим сказати, що ширина чашолистка була найважливішою, а потім довжина чашолистка?
Гвідо

10
Щоб зрозуміти, які особливості важливі, потрібно звернути увагу на співвідношення. Наприклад, ширина чашолистка та PC-2 сильно корелюють (навпаки), оскільки коефіцієнт кореляції становить -0,92. З іншого боку, довжина пелюстки та ПК-2 взагалі не корелюють, оскільки кор-коефіцієнт становить -0,02. Отже, PC-2 зростає із зменшенням ширини чашолистка, і PC-2 не залежить від змін довжини пелюстки. Тобто для ПК-2 ширина чашолистка важлива, тоді як довжина пелюстки - ні. Той самий аналіз, який ви можете провести для інших змінних, враховуючи коефіцієнт кореляції, знаходиться в інтервалі [-1, 1]
Рафа

Корисна відповідь! Для своїх цілей я хотів, щоб кадр даних був повернутий таким чином, щоб компоненти були стовпцями. Я використовувавpd.DataFrame(pca.components_.T, index=data_scaled.columns)
Лора

Якщо ви хочете отримати його single most important feature nameна певному ПК (або на всіх ПК), див. Мою відповідь у кінці цієї сторінки.
seralouk

51

Редагувати: як коментували інші, ви можете отримати однакові значення з .components_атрибута.


Кожен головний компонент є лінійною комбінацією вихідних змінних:

pca-coef

де X_is - вихідні змінні, а Beta_is - відповідні ваги або так звані коефіцієнти.

Щоб отримати ваги, ви можете просто передати матрицю ідентичності 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
Чудова та вичерпна відповідь, велике спасибі!
mazieres

5
У цій матриці ідентичності немає потреби: ваша coefтака сама, як pca.components_.T. оцінювачі scikit-learn завжди вкладають свої вивчені параметри в загальнодоступні атрибути.
Fred Foo

4
Чому б не використовувати безпосередньо pca.components_?
exAres 02

2
Використання ідентифікаційної матриці не працює, оскільки функція зворотного перетворення додає емпіричне середнє значення кожної ознаки. Результат надає однакову вагу (коефіцієнти) усім вихідним змінним. (Див. Цю відповідь ). Використовуючи pca.components_, ви отримуєте правильну відповідь.
Рахул Мурмурія,

33

Формулювання цього питання нагадує мені про нерозуміння принципового аналізу компонентів, коли я вперше намагався це зрозуміти. Я хотів би пройти через це тут з надією, що інші не витратять стільки часу на дорогу в нікуди, як я, перш ніж копійка остаточно впала.

Поняття "відновлення" імен функцій передбачає, що PCA ідентифікує ті функції, які є найбільш важливими в наборі даних. Це не зовсім точно.

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

Щоб ввести цю теорію в практичні приклади зразка коду @ Rafa:

# 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у прикладі @ Rafa, повідомляється sepal_widthбільше, ніж будь-який інший стовпець, але значення в PC-2і data_scaled['sepal_width']не однакові.

Таким чином, хоча цікаво з’ясувати, наскільки кожен стовпець у вихідних даних вносив свій внесок у компоненти набору даних після PCA, поняття „відновлення” назв стовпців трохи вводить в оману, і, безумовно, надовго ввів мене в оману. Єдина ситуація, коли може бути збіг між стовпцями PCA та оригінальними стовпцями, якщо кількість основних компонентів буде встановлена ​​на таку ж кількість, що і стовпці в оригіналі. Однак не було б сенсу використовувати однакову кількість стовпців, оскільки дані не змінилися б. Ви б лише поїхали туди, щоб як би повернутися.


Дякую Азіз. Я рада, що ви змогли щось від цього отримати.
амненелі

Дякую. Це заощадило мені багато часу, оскільки я принципово неправильно зрозумів, що робить алгоритм.
Томас

Я був у дорозі в нікуди .. Дякую
Девід Холкуп

9

Важливими ознаками є ті, які впливають більше на компоненти і, отже, мають велике абсолютне значення / коефіцієнт / навантаження на компонент.

Отримати 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

Висновок / Пояснення:

Тож на PC1 названа функція eє найважливішою, а на PC2 - d.


6

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.