НейроАгент

Реализация параллельного анализа Хорна для PCA на ковариационных матрицах

Полное руководство по реализации параллельного анализа Хорна для PCA на ковариационных матрицах в R. Устранение проблем с собственными значениями и определение оптимального сохранения компонентов с правильными настройками параметров.

Как правильно реализовать параллельный анализ Хорна для определения количества главных компонент в PCA на основе ковариационной матрицы?

Я пытаюсь выполнить параллельный анализ (Horn, 1965) для определения количества значимых главных компонент в PCA, основанном на ковариационной матрице (а не на корреляционной матрице). Я пытался использовать пакет nFactors, но не смог правильно интерпретировать или реализовать его. Когда я запустил анализ, все эмпирические собственные значения оказались ниже смоделированных, что кажется неверным.

Какие шаги по устранению неполадок я должен попробовать дальше? Вот моя текущая реализация:

r
# Код для выполнения параллельного анализа Хорна для PCA на ковариационной матрице

# Загрузка необходимых библиотек ####
library(openxlsx)
library(nFactors)

# Импорт набора данных
data <- read.xlsx("data.xlsx")

# Количество наблюдений и переменных
n_subjects <- nrow(data)
n_variables <- ncol(data)

# Расчет ковариационной матрицы
cov_mat <- cov(data, use = "pairwise.complete.obs")
cov_mat

# Расчет стандартного отклонения переменных
sd_vec <- sqrt(diag(cov_mat))
sd_vector <- as.vector(sd_vec)

# Расчет собственных значений
eigen_cov <- eigen(cov_mat)$values
eigen_cov <- as.vector(eigen_cov)

# Выполнение параллельного анализа

# Квантиль распределения собственных значений 
sim_qevpea <- parallel(
  var = n_variables,
  subject = n_subjects,
  rep = 1000,      
  quantile = 0.95, 
  sd = diag(sd_vector))$eigen$qevpea

# Среднее значение распределения собственных значений
sim_mevpea <- parallel(
  var = n_variables,
  subject = n_subjects,
  rep = 1000,      
  quantil = 0.95, 
  sd = diag(sd_vector))$eigen$mevpea

# Объединение результатов в dataframe
sim_mevpea <- as.data.frame(sim_mevpea)
sim_qevpea <- as.data.frame(sim_qevpea)
obs_eigenvalues <- as.data.frame(eigen_cov)
sim_eig_obs_eig <- cbind(sim_mevpea, sim_qevpea, obs_eigenvalues)

# Результаты
    sim_mevpea  sim_qevpea    eigen_empiric
1  0.016609276 0.018170467 2.755510e-04
2  0.014469410 0.015579270 2.351656e-04
3  0.012966035 0.013853537 1.452651e-04
4  0.011738829 0.012546877 1.289419e-04
5  0.010746659 0.011467116 1.105977e-04
6  0.009892356 0.010519131 8.850754e-05
7  0.009101438 0.009717212 6.505378e-05
8  0.008403761 0.008964388 5.331106e-05
9  0.007787579 0.008299819 4.988057e-05
10 0.007208755 0.007668394 3.628711e-05
11 0.006675843 0.007149570 2.814191e-05
12 0.006194959 0.006593400 2.418505e-05
13 0.005733585 0.006138405 1.627334e-05
14 0.005284943 0.005671669 1.355602e-05
15 0.004858114 0.005257232 1.123874e-05
16 0.004453399 0.004805642 9.359437e-06
17 0.004045374 0.004410657 7.997094e-06
18 0.003625045 0.004021005 7.779925e-06
19 0.003190694 0.003575597 1.775028e-06
20 0.002681099 0.003138437 6.740691e-07

Есть ли проблема с моей реализацией? Существуют ли альтернативные подходы или исправления, которые я должен рассмотреть?

НейроАгент

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

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

Содержание

Понимание проблемы в вашей реализации

В вашей текущей реализации есть несколько проблем, объясняющих, почему все эмпирические собственные значения ниже смоделированных:

  1. Опечатка в параметре: Во втором вызове parallel() вы использовали quantil вместо quantile
  2. Проблема масштаба собственных значений: Собственные значения из ковариационных матриц обычно гораздо больше, чем из корреляционных матриц, но ваши результаты показывают чрезвычайно малые значения
  3. Указание стандартного отклонения: Параметр sd должен быть правильно указан для анализа ковариационной матрицы
  4. Масштабирование данных: Собственные значения указывают на то, что ваши данные могут находиться на очень маленьком масштабе или есть проблема нормализации

Правильные шаги реализации

Вот как правильно реализовать параллельный анализ Хорна для ковариационных матриц:

1. Подготовьте ваши данные правильно

r
# Загрузка необходимых библиотек
library(nFactors)
library(psych)

# Импорт ваших данных
data <- read.xlsx("data.xlsx")

# Убедитесь, что ваши данные правильно масштабированы
# Важно: НЕ стандартизируйте данные для PCA ковариационной матрицы
n_subjects <- nrow(data)
n_variables <- ncol(data)

# Вычисление ковариационной матрицы
cov_mat <- cov(data, use = "pairwise.complete.obs")

# Вычисление собственных значений из ваших фактических данных
eigen_observed <- eigen(cov_mat)$values

2. Реализуйте параллельный анализ с правильными параметрами

r
# Выполните параллельный анализ для ковариационной матрицы
results <- parallel(
  var = n_variables,
  subject = n_subjects,
  rep = 1000,          # Количество репликаций
  quantile = 0.95,     # Порог 95-го процентиля
  model = "components", # Модель PCA
  sd = sqrt(diag(cov_mat)) # Критически важно: использовать фактические стандартные отклонения
)

# Извлечение смоделированных собственных значений
simulated_eigen_mean <- results$eigen$mevpea
simulated_eigen_quantile <- results$eigen$qevpea

3. Сравните и определите количество сохраняемых компонент

r
# Создание фрейма данных для сравнения
comparison <- data.frame(
  Component = 1:n_variables,
  Observed = eigen_observed,
  Simulated_Mean = simulated_eigen_mean,
  Simulated_95th = simulated_eigen_quantile,
  Retain = eigen_observed > simulated_eigen_quantile
)

# Просмотр результатов
print(comparison)

Альтернативные подходы

Использование пакета paran

Пакет paran специально разработан для параллельного анализа Хорна:

r
library(paran)

# Выполнение параллельного анализа
pa_result <- paran(
  cov_mat,
  n.iter = 1000,
  cent = 0.05,
  quantile = TRUE
)

# Построение графика результатов
plot(pa_result)

# Получение рекомендуемого количества компонент
pa_result$nfact

Ручная реализация для лучшего контроля

r
# Ручная реализация параллельного анализа
set.seed(123)  # Для воспроизводимости
n_sim <- 1000
sim_eigen <- matrix(NA, nrow = n_variables, ncol = n_sim)

for (i in 1:n_sim) {
  # Генерация случайных данных с той же ковариационной структурой
  random_data <- matrix(rnorm(n_subjects * n_variables), 
                       nrow = n_subjects, ncol = n_variables)
  
  # Масштабирование для соответствия исходным дисперсиям (критически важно для ковариационной матрицы)
  random_data_scaled <- sweep(random_data, 2, 
                             sqrt(diag(cov_mat)), `*`)
  
  # Вычисление ковариационной матрицы и собственных значений
  cov_sim <- cov(random_data_scaled)
  sim_eigen[, i] <- eigen(cov_sim)$values
}

# Вычисление среднего и квантилей
sim_mean <- apply(sim_eigen, 1, mean)
sim_95th <- apply(sim_eigen, 1, quantile, probs = 0.95)

# Сравнение с наблюдаемыми собственными значениями
comparison <- data.frame(
  Component = 1:n_variables,
  Observed = eigen_observed,
  Simulated_Mean = sim_mean,
  Simulated_95th = sim_95th,
  Retain = eigen_observed > sim_95th
)

Устранение распространенных проблем

Проблема 1: Все собственные значения чрезвычайно малы

Проблема: Ваши собственные значения находятся в диапазоне 10^-6 до 10^-3, что необычно мало.

Решение:

  • Проверьте масштаб исходных данных
  • Убедитесь, что вы не стандартизируете данные перед вычислением ковариации
  • Убедитесь, что ваши данные не нормированы или масштабированы заранее

Проблема 2: Эмпирические собственные значения всегда ниже смоделированных

Проблема: Это указывает на фундаментальную проблему в вашем подходе.

Решения:

  • Исправьте опечатку в параметре: Измените quantil на quantile
  • Проверьте указание стандартного отклонения: Используйте sd = sqrt(diag(cov_mat))
  • Проверьте целостность данных: Убедитесь, что ваша ковариационная матрица вычислена правильно
  • Увеличьте количество репликаций: Попробуйте rep = 2000 для более стабильных оценок

Проблема 3: Несогласованные результаты между запусками

Проблема: Результаты параллельного анализа значительно различаются между запусками.

Решение:

  • Установите seed для воспроизводимости: set.seed(123)
  • Увеличьте количество репликаций: rep = 2000
  • Используйте более высокий квантиль: quantile = 0.99

Полный пример кода на R

r
# Полный параллельный анализ Хорна для PCA ковариационной матрицы

# Загрузка библиотек
library(nFactors)
library(psych)
library(openxlsx)

# Установка seed для воспроизводимости
set.seed(123)

# Импорт данных
data <- read.xlsx("data.xlsx")

# Базовая информация о данных
cat("Количество наблюдений:", nrow(data), "\n")
cat("Количество переменных:", ncol(data), "\n")

# Вычисление ковариационной матрицы (НЕ стандартизируйте для PCA ковариации)
cov_mat <- cov(data, use = "pairwise.complete.obs")

# Вычисление наблюдаемых собственных значений
eigen_observed <- eigen(cov_mat)$values

# Выполнение параллельного анализа
results <- parallel(
  var = ncol(data),
  subject = nrow(data),
  rep = 2000,          # Увеличенное количество репликаций для стабильности
  quantile = 0.95,     # 95-й процентиль
  model = "components",
  sd = sqrt(diag(cov_mat))  # Критический параметр для ковариационных матриц
)

# Извлечение смоделированных собственных значений
sim_mean <- results$eigen$mevpea
sim_95th <- results$eigen$qevpea

# Создание фрейма данных для сравнения
comparison <- data.frame(
  Component = 1:length(eigen_observed),
  Observed_Eigenvalue = eigen_observed,
  Simulated_Mean = sim_mean,
  Simulated_95th = sim_95th,
  Difference = eigen_observed - sim_95th,
  Retain_Component = eigen_observed > sim_95th
)

# Отображение результатов
print("Сравнение собственных значений:")
print(comparison)

# Определение количества компонент для сохранения
n_components <- sum(eigen_observed > sim_95th)
cat("\nРекомендуемое количество компонент для сохранения:", n_components, "\n")

# Создание визуализации
plot(1:length(eigen_observed), eigen_observed, 
     type = "b", pch = 19, col = "blue",
     xlab = "Номер компоненты", 
     ylab = "Собственное значение",
     main = "Параллельный анализ Хорна - Ковариационная матрица")
lines(1:length(eigen_observed), sim_mean, 
      type = "b", pch = 17, col = "red")
lines(1:length(eigen_observed), sim_95th, 
      type = "b", pch = 15, col = "green")
legend("topright", 
       legend = c("Наблюдаемые", "Средние смоделированные", "95-й процентиль смоделированных"),
       col = c("blue", "red", "green"),
       pch = c(19, 17, 15))

# Дополнительные диагностические графики
par(mfrow = c(2, 2))
plotuScree(eigen_observed, main = "График крутизны")
plotuScree(sim_95th, main = "95-й процентиль смоделированных")
hist(eigen_observed, main = "Распределение наблюдаемых собственных значений")
hist(sim_95th, main = "Распределение 95-го процентиля смоделированных")
par(mfrow = c(1, 1))

Интерпретация результатов

При интерпретации результатов параллельного анализа:

  1. Правило сохранения: Сохраняйте компоненты, где наблюдаемые собственные значения превышают смоделированные 95-процентильные собственные значения
  2. Упорядочивание компонент: Компоненты упорядочены по величине собственных значений (от большего к меньшему)
  3. Принятие решений: Первая компонента, где наблюдаемое собственное значение падает ниже смоделированного порога, указывает на оптимальное количество компонент

Пример интерпретации:

Компонента 1: Наблюдаемое = 5.2, С��елированное_95-е = 1.8 → СОХРАНИТЬ
Компонента 2: Наблюдаемое = 2.1, С��елированное_95-е = 1.5 → СОХРАНИТЬ
Компонента 3: Наблюдаемое = 1.2, С��елированное_95-е = 1.3 → НЕ СОХРАНЯТЬ

В этом примере вы сохранили бы 2 компоненты.

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

Источники

  1. Stack Overflow - Параллельный анализ Хорна для ковариационной матрицы
  2. Блог SAS - Параллельный анализ для сохранения главных компонент
  3. Документация пакета nFactors
  4. Оригинальная статья Хорна (1965)
  5. Википедия - Параллельный анализ
  6. Документация пакета paran
  7. ResearchGate - Реализация параллельного анализа Хорна