Я отримую "стрибкові" завантаження в Rola-застосуванні PCA в Р. Чи можу я це виправити?


20

Я маю 10 років даних про щоденні прибутки для 28 різних валют. Я хочу витягнути перший основний компонент, але замість того, щоб використовувати PCA протягом 10 років, я хочу застосувати 2-річне вікно, тому що поведінка валют змінюється, і тому я хочу це відобразити. Однак у мене є основна проблема, тобто те, що і функції princomp (), і prcomp () часто переходять від позитивних до негативних навантажень в суміжних аналізах PCA (тобто один день один від одного). Подивіться графік завантаження валюти EUR:

введіть тут опис зображення

Зрозуміло, я не можу це використати, оскільки сусідні навантаження перейдуть з позитивного на негативне, тому моя серія, яка їх використовує, буде помилковою. Тепер подивіться на абсолютне значення завантаження валюти EUR:

введіть тут опис зображення

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

Чи є спосіб вирішити цю проблему? Чи можу я змусити орієнтацію власного вектора завжди бути однаковою в сусідніх PCA?

До речі, ця проблема також виникає з функцією FactoMineR PCA (). Код для відклику тут:

rollapply(retmat, windowl, function(x) summary(princomp(x))$loadings[, 1], by.column = FALSE, align = "right") -> princomproll

3
Чи можете ви пояснити, що ви маєте на увазі під «орієнтацією» власного вектора? Наскільки я знаю, немає такої речі, яка б була суттєвою для даних. (Це одна з причин, чому різні програми створюватимуть різні нормовані власні вектори.) Тож звучить так, ніби ви просите про щось, що не існує і є безглуздим.
whuber

1
Ну в один день я отримаю такі навантаження: -0,2 ZAR +0,8 USD +0,41 ..... 28 валют. А наступного дня я отримаю +0,21 ZAR -0,79 USD -0,4 тощо. Отже, вісь, на яку PCA обрала обертати дані, орієнтована точно на другий день, порівняно з першим днем. Це спричиняє ці завантаження стрибають, і я хотів би його якось уникнути ...... Вибачте, якщо моя термінологія вводить в оману. Я розумію, що код PCA насправді не хвилює орієнтацію на осі, якщо він узгоджується з навантаженнями на один день , але мені потрібно, щоб він був узгодженим протягом декількох днів.
Томас Браун

1
маючи на увазі, що від одного дня до другого, враховуючи перебіг 2-річного періоду щоденних даних, ми повинні мати дуже-дуже схожий PCA.
Томас Браун

Думаю, що у вас є проблеми в тому, що ця ідея про реалізацію не має сенсу. У мене немає іншого рішення, як шукати щось інше, яке може досягти ваших цілей (не впевнені, що вони є) і є розумним.
Майкл Р. Черник

EUR -0.2 ZAR +0.8 USD +0.41і EUR +0.21 ZAR -0.79 USD -0.4 це дуже і дуже схожі. Ви просто інвертуєте вхід у будь-який із двох результатів.
ttnphns

Відповіді:


22

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

Ось реалізація. (Я не знайомий zoo, що могло б дати більш елегантне рішення.)

require(zoo)
amend <- function(result) {
  result.m <- as.matrix(result)
  n <- dim(result.m)[1]
  delta <- apply(abs(result.m[-1,] - result.m[-n,]), 1, sum)
  delta.1 <- apply(abs(result.m[-1,] + result.m[-n,]), 1, sum)
  signs <- c(1, cumprod(rep(-1, n-1) ^ (delta.1 <= delta)))
  zoo(result * signs)
}

Як приклад, давайте проведемо випадкову прогулянку в ортогональній групі та трохи джиртуємо для зацікавлення:

random.rotation <- function(eps) {
  theta <- rnorm(3, sd=eps)
  matrix(c(1, theta[1:2], -theta[1], 1, theta[3], -theta[2:3], 1), 3)
}
set.seed(17)
n.times <- 1000
x <- matrix(1., nrow=n.times, ncol=3)
for (i in 2:n.times) {
  x[i,] <- random.rotation(.05) %*% x[i-1,]
}

Ось прокат PCA:

window <- 31
data <- zoo(x)
result <- rollapply(data, window, 
  function(x) summary(princomp(x))$loadings[, 1], by.column = FALSE, align = "right")
plot(result)

Оригінал

Тепер виправлена ​​версія:

plot(amend(result))

Змінено


тivi+1i+1vii1-1vi+1. Здається, ваш алгоритм трохи інший. Як би це працювало так само?
амеба каже, що відновіть Моніку

@amoeba Хоча я не зовсім впевнений, що саме ти робиш, це звучить як деякі ідеї, обговорені у відповіді Девіда Дж. Гарріса, та коментарі, що слідують за ним. Дивіться, зокрема, мій коментар на сайті stats.stackexchange.com/questions/34396/… .
whuber

2
@Art, так як я розумію, ви хочете виправити знак компонента на основі деяких зовнішніх (зовнішніх до PCA) уподобань. Це добре, але саме до цього слід підходити. Спочатку зробіть ковзну річ PCA, переконавшись у відповідності знаків. А потім вирішіть, виходячи з деяких додаткових критеріїв, перевертати весь компонент чи ні. Наприклад, ви можете співвіднести це з євро тенденцією, і якщо кореляція негативна, переверніть компонент. Або щось подібне. Це повністю залежить від вашої конкретної програми та знань вашого домену.
амеба каже, що поверніть Моніку

1
Я згоден з тлумаченням та рекомендацією @ amoeba.
whuber

1
@amoeba: так, ви маєте рацію з цього приводу, хоча, я наївно думав, що може бути якесь загальне рішення, яке не залежить від конкретного часового ряду, щось на кшталт "реальної орієнтації вектора" :) все одно, дякую за допомогу та пропозиції
Анонім

8

@whuber має рацію, що не існує орієнтації, яка є сутнісною даних, але ви все одно можете стверджувати, що ваші власні вектори мають позитивну кореляцію з деяким еталонним вектором.

Наприклад, ви можете зробити навантаження на долар позитивними на всіх власних векторах (тобто, якщо завантаження долара США негативне, переверніть знаки всього вектора). Загальний напрямок вектора все ще довільний (оскільки замість цього ви могли використовувати EUR або ZAR в якості посилань), але перші кілька осей вашого PCA, ймовірно, не будуть стрибати приблизно стільки ж - тим більше, що ваші прокатні вікна такі довго.


7
Гарна ідея. Я спробував це першим (напевно, поки ви публікували цю відповідь :-). Проблема в тому, що інші навантаження можуть стрибати навколо. Щоб виправити це, ґрунтуйте вибір знаків на найбільшому завантаженні. Досі немає кісток: навантаження все одно можуть стрибати. Хитрість полягає в тому, щоб кожен раз вибирати орієнтацію, яка створює найменше збурення у векторі навантажень від попереднього часу.
whuber

4
@whuber Приємна робота.
Девід Дж. Харріс

1
Правильно, знак навантажень не має значення (орієнтація). Щось не було вирішено, це те, що якщо ви виконуєте це в різних програмних пакетах, різниця між пакетами полягає в тому, що одна програма може спричинити негативні (позитивні) ознаки на певних завантаженнях, а інша призводить до позитивних (негативних) ознак для тих же завантажень. Таким чином, ознаки кінцевих результатів у діаграмі 3-серії вище можна перевернути, використовуючи інший пакет. Навантаження опорного вектора також може мати зміни знаків - і це рішення було б невірним.
JoleT

@LEP: Я зіткнувся з тією ж проблемою, що і з інверсією, можливо, ви вже знайшли рішення для цього питання - як з’ясувати, що перший вектор правильний і переконатися, що решта буде вирівняна до нього належним чином - quant.stackexchange.com/questions / 3094 /… ?
Анонім

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

1

Що я зробив, це обчислити відстань L1 між послідовними власними векторами. Після нормалізації цієї матриці я вибираю пороговий показник az, наприклад, 1, так що якщо в будь-якому новому прокаті зміна перевищує цей поріг, я перевертаю власний вектор, коефіцієнти та навантаження, щоб мати послідовність у вікні прокатки. Особисто мені не подобається примушувати задані знаки в деяких кореляціях, оскільки вони можуть бути дуже мінливими в залежності від макро драйверів.

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