Як обчислити основні компоненти, обернені варімакс в R?


13

Я провів PCA на 25 змінних і вибрав топ-7 ПК за допомогою prcomp.

prc <- prcomp(pollutions, center=T, scale=T, retx=T)

Тоді я здійснив обертання varimax на цих компонентах.

varimax7 <- varimax(prc$rotation[,1:7])

А тепер я хочу, щоб varimax обертав дані, обернені PCA (оскільки це не частина об'єкта varimax - лише матриця завантаження та матриця обертання). Я прочитав, що для цього ви помножите транспозицію матриці обертання на перенесення даних, щоб я це зробив:

newData <- t(varimax7$rotmat) %*% t(prc$x[,1:7])

Але це не має сенсу, оскільки розміри перенесеної матриці вище 7×7 та 7×16933 відповідно, і тому мені залишиться матриця всього 7 рядків, а не 16933 рядків… хтось знає, що я я тут роблю неправильно чи яким повинен бути мій останній рядок? Мені просто потрібно перенести назад після цього?

Відповіді:


22

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

@ Відповідь FTusell передбачає, що обертання varimax застосовується до власних векторів (не для навантажень). Це було б досить нетрадиційно. Будь ласка, дивіться детальну інформацію про PCA + varimax для деталей: Чи PCA супроводжується обертанням (наприклад, varimax), як і раніше PCA? Коротко, якщо ми подивимось на SVD матриці даних , то повернути навантаження означає вставити R R для деякої матриці обертання R таким чином: X = ( U R ) ( R S V ) .X=USVRRRX=(UR)(RSV).

Якщо обертання застосовується до навантажень (як це зазвичай відбувається), то існує щонайменше три простих способи обчислити варімакс-обертові ПК у R:

  1. Вони легко доступні за допомогою функції psych::principal(демонструючи, що це дійсно стандартний підхід). Зауважте, що він повертає стандартизовані бали , тобто всі ПК мають одиничну дисперсію.

  2. Можна вручну використовувати varimaxфункцію обертання вантажів, а потім використовувати нові обертові вантажі для отримання балів; потрібно множити дані із переміщеною псевдоінверсією обертових навантажень (див. формули у цій відповіді від @ttnphns ). Це також дасть стандартизовані бали.

  3. Можна використовувати varimaxфункцію обертання навантажень, а потім використовувати $rotmatматрицю обертання для обертання стандартизованих балів, отриманих за допомогою prcomp.

Усі три методи дають однаковий результат:

irisX <- iris[,1:4]      # Iris data
ncomp <- 2

pca_iris_rotated <- psych::principal(irisX, rotate="varimax", nfactors=ncomp, scores=TRUE)
print(pca_iris_rotated$scores[1:5,])  # Scores returned by principal()

pca_iris        <- prcomp(irisX, center=T, scale=T)
rawLoadings     <- pca_iris$rotation[,1:ncomp] %*% diag(pca_iris$sdev, ncomp, ncomp)
rotatedLoadings <- varimax(rawLoadings)$loadings
invLoadings     <- t(pracma::pinv(rotatedLoadings))
scores          <- scale(irisX) %*% invLoadings
print(scores[1:5,])                   # Scores computed via rotated loadings

scores <- scale(pca_iris$x[,1:2]) %*% varimax(rawLoadings)$rotmat
print(scores[1:5,])                   # Scores computed via rotating the scores

Це дає три однакових виходи:

1 -1.083475  0.9067262
2 -1.377536 -0.2648876
3 -1.419832  0.1165198
4 -1.471607 -0.1474634
5 -1.095296  1.0949536

Примітка:varimax функція R використовує normalize = TRUE, eps = 1e-5параметри за замовчуванням ( дивіться в документації ). Можливо, захочеться змінити ці параметри (зменшити epsтолерантність та подбати про нормалізацію Kaiser), порівнюючи результати з іншим програмним забезпеченням, таким як SPSS. Я дякую @GottfriedHelms за те, що донесли це до моєї уваги. [Примітка: ці параметри працюють при передачі varimaxфункції, але не працюють при передачі psych::principalфункції. Здається, це помилка, яку виправлять.]


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

@amoeba Я намагаюся зробити PCA + varimax за допомогою principal, prcompі princomp, але отримані висновки щодо завантаження / дослідження сильно відрізняються один від одного. Наскільки я розумію, prcomp та princomp не повертають стандартизованих балів та навантажень. Моє запитання: який найкращий підхід? Я дійсно хочу стандартизованих результатів? Чи не за моїм кодом pca_iris <- prcomp(irisX, center=T, scale=T)слідує varimax(pca_iris$rotation)$loadingsтакий же правильний, як ваш вище?
JMarcelino

@JMarcelino, ні, ваш код робить варімакс-обертання на власних векторах, а не на навантаженнях. Це не так, як обертання varimax зазвичай розуміється чи застосовується.
Амеба каже, що поверніть Моніку

1
X=USVRRRX=URRSVL=VSR/n1T=URn1
X=TL.
XLT
T=X(L)+=X(L+).

1
Я отримав відповідь керівника пакету, професора Ревелла. Це здається помилкою в обробці параметрів у principalпроцедурі, яка завжди обчислюється з Kaiser-нормалізацією і eps = 1e-5. Поки немає інформації, чому на r-fiddle.org версія працює коректно. Тож варто чекати оновлень - і я повинен видалити всі застарілі коментарі. амеба - добре було б відповідно оновити зауваження у своїй відповіді. Дякую за всю співпрацю!
Готфрід Гельмс

9

Вам потрібно використовувати матрицю $loadings, а не $rotmat:

 x <- matrix(rnorm(600),60,10)
 prc <- prcomp(x, center=TRUE, scale=TRUE)
 varimax7 <- varimax(prc$rotation[,1:7])
 newData <- scale(x) %*% varimax7$loadings

Матриця $rotmat- це ортогональна матриця, яка створює нові навантаження з невратованих.

EDIT станом на 12 лютого 2015 року:

n×mX

X=USVT
VXX
X=(UST)(TTVT)=UV
TVVUX(V)Tk<mkX
X(UkSk)(VkT)
X(UkSkTk)(TkTVkT)=UkVk
Vkk×nXVk, а краще нам вдатися до одного з рішень, описаних @amoeba.

Іншими словами, запропоноване мною рішення є правильним лише в конкретному випадку, коли воно було б марним і безглуздим.

Щиро дякую @amoeba за те, що він зрозумів мені цю справу; Я живу з цим хибним уявленням роками.

SVLVSviTX (i=1,,m)vi=1

ДОПОМОГА РЕДАКЦІЯ 12 лютого 2015 року

Як вказує @amoeba, хоча є прямокутним, рішення, яке я запропонував, все ще може бути прийнятним: дасть одиничну матрицю і . Тож все, як видається, залежить від визначення балів, які варто віддати перевагу. V k ( V k ) T X ( V k ) TU kVkVk(Vk)TX(Vk)TUk


1
Ах правдиво. Я заплутався, тому що навантаження для prcomp називається "обертання", повинно було б краще прочитати допомогу. Оскільки я використовую "center = TRUE, scale = TRUE" у методі prcomp, чи означає це, що насправді я повинен бути центром і масштабуванням своїх даних, перш ніж помножувати їх на мої варімакс $ завантаження?
Скотт

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

2
Я забув згадати, що ви можете поглянути на функцію фактанал, якщо ви цього ще не зробили. Він робить факторний аналіз, а не основні компоненти, але поверне бали безпосередньо.
Ф. Тузелл

2
-1. Я вважаю, що ця відповідь є невірною, і я розмістив власну відповідь, щоб продемонструвати її. Не можна отримати поворотні бали за допомогою ортогональної проекції на обертові вантажі (оскільки вони вже не є ортогональними). Найпростіший спосіб отримати правильні оцінки - використовувати psych::principal. [Окрім цього, я відредагував вашу відповідь, щоб вставити масштаб, як обговорювалося в коментарях вище.]
Амеба каже Відновити Моніку

1
Вибач, моя погана. Я мав на увазі є . Я зараз це виправлю. І ... так, тепер, коли я дивлюся на це, має ортогональні стовпці, так що все одно отримає нам матрицю одиниць, правда? Якщо так, я не ввів в оману оригінальний плакат, ви піднімаєте вантаж з моєї душі! k × n V ( T T k V T k ) ( V k T k )Vkk×nV(TkTVkT)(VkTk)
Ф. Тузелл,

0

Я шукав рішення, яке працює для PCA, виконане за допомогою ade4 .

Знайдіть функцію нижче:

library(ade4)

irisX <- iris[,1:4]      # Iris data
ncomp <- 2
# With ade4
dudi_iris <- dudi.pca(irisX, scannf = FALSE, nf = ncomp)

rotate_dudi.pca <- function(pca, ncomp = 2) {

  rawLoadings <- as.matrix(pca$c1[,1:ncomp]) %*% diag(sqrt(pca$eig), ncomp, ncomp)
  pca$c1 <- rawLoadings
  pca$li <- scale(pca$li[,1:ncomp]) %*% varimax(rawLoadings)$rotmat

  return(pca)
} 
rot_iris <- rotate_dudi.pca(pca = dudi_iris, ncomp = ncomp)
print(rot_iris$li[1:5,])                   # Scores computed via rotating the scores
#>        [,1]       [,2]
#> 1 -1.083475 -0.9067262
#> 2 -1.377536  0.2648876
#> 3 -1.419832 -0.1165198
#> 4 -1.471607  0.1474634
#> 5 -1.095296 -1.0949536

Створено 2020-01-14 пакетом reprex (v0.3.0)

Сподіваюся, що це допоможе!


Потрібно використовувати цей простір для відповіді.
Майкл Р. Черник

Мені здалося, що справедливо додати відповідь для повноти. Як і для цього питання: stackoverflow.com/questions/6862742/draw-a-circle-with-ggplot2 . Я буду радий передати свою пропозицію, якщо це необхідно.
Ален Данет

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