Для случайной матрицы разве SVD не должен вообще ничего объяснять? Что я делаю неправильно?

13

Если бы я построил двумерную матрицу, состоящую полностью из случайных данных, я ожидал бы, что компоненты PCA и SVD по существу ничего не объясняют.

Вместо этого кажется, что первый столбец SVD, кажется, объясняет 75% данных. Как это может быть? Что я делаю неправильно?

Вот сюжет:

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

Вот код R:

set.seed(1)
rm(list=ls())
m <- matrix(runif(10000,min=0,max=25), nrow=100,ncol=100)
svd1 <- svd(m, LINPACK=T)
par(mfrow=c(1,4))
image(t(m)[,nrow(m):1])
plot(svd1$d,cex.lab=2, xlab="SVD Column",ylab="Singluar Value",pch=19)

percentVarianceExplained = svd1$d^2/sum(svd1$d^2) * 100
plot(percentVarianceExplained,ylim=c(0,100),cex.lab=2, xlab="SVD Column",ylab="Percent of variance explained",pch=19)

cumulativeVarianceExplained = cumsum(svd1$d^2/sum(svd1$d^2)) * 100
plot(cumulativeVarianceExplained,ylim=c(0,100),cex.lab=2, xlab="SVD column",ylab="Cumulative percent of variance explained",pch=19)

Обновить

Спасибо, Аарон. Исправление, как вы заметили, состояло в том, чтобы добавить масштабирование к матрице так, чтобы числа центрировались вокруг 0 ​​(т.е. среднее значение было 0).

m <- scale(m, scale=FALSE)

Вот исправленное изображение, показывающее для матрицы со случайными данными первый столбец SVD, близкий к 0, как и ожидалось.

Исправленное изображение

Контанго
источник
4
[0,1]100р100рNN1/3N/3-(N-1)/121/12(N/3-(N-1)/12)/(N/3)знак равно3/4+1/(4N)Nзнак равно10075,25

Ответы:

11

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

m <- matrix(runif(10000,min=0,max=25), nrow=100,ncol=100)
m <- scale(m, scale=FALSE)

m <- matrix(runif(10000,min=-25,max=25), nrow=100,ncol=100)
Аарон оставил переполнение стека
источник
3
Вы подняли хороший вопрос, но я думаю, что это говорит только часть истории. Действительно, я бы предположил, что ОП попробует каждый из них и все равно будет удивлен результатом. Дело в том, что поскольку сингулярные значения упорядочены в выходных данных, они не будут выглядеть (и даже не будут) равномерно распределенными, как можно было бы наивно ожидать от «случайных» данных. Распределение Марченко-Пастура определяет их поведение в этом случае.
кардинал
@ Аарон Спасибо, ты был абсолютно прав. Я добавил график исправленных результатов выше, чтобы показать, насколько красив результат.
Contango,
1
@cardinal Спасибо за ваш комментарий, вы абсолютно правы (см. график, полученный с помощью исправленного кода, выше). Я полагаю, что значения SVD станут менее равномерно распределенными, поскольку матрица становится меньше, поскольку меньшая матрица будет иметь больше шансов иметь шаблоны, которые не будут сдавлены по закону больших чисел.
Contango
3

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

Я использую prcompвместо svdразложения матрицы, но результаты аналогичны:

set.seed(1)
m <- matrix(runif(10000,min=0,max=25), nrow=100,ncol=100)

S <- svd(scale(m, center = TRUE, scale=FALSE))
P <- prcomp(m, center = TRUE, scale=FALSE)
plot(S$d, P$sdev) # linearly related

Сравнение нулевой модели выполняется по центрированной матрице ниже:

library(sinkr) # https://github.com/marchtaylor/sinkr

# centred data
Pnull <- prcompNull(m, center = TRUE, scale=FALSE, nperm = 100)
Pnull$n.sig
boxplot(Pnull$Lambda[,1:20], ylim=range(Pnull$Lambda[,1:20], Pnull$Lambda.orig[1:20]), outline=FALSE, col=8, border="grey50", log="y", main=paste("m (center=FALSE); n sig. =", Pnull$n.sig))
lines(apply(Pnull$Lambda, 2, FUN=quantile, probs=0.95))
points(Pnull$Lambda.orig[1:20], pch=16)

Ниже приведен блок-график перестановочной матрицы с 95-процентным квантилем каждого сингулярного значения, показанного сплошной линией. Исходные значения PCA mявляются точками. все из которых лежат ниже линии 95% - таким образом, их амплитуда неотличима от случайного шума.

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

Та же процедура может быть выполнена для нецентрированной версии mс тем же результатом - без значительных единичных значений:

# centred data
Pnull <- prcompNull(m, center = FALSE, scale=FALSE, nperm = 100)
Pnull$n.sig
boxplot(Pnull$Lambda[,1:20], ylim=range(Pnull$Lambda[,1:20], Pnull$Lambda.orig[1:20]), outline=FALSE, col=8, border="grey50", log="y", main=paste("m (center=TRUE); n sig. =", Pnull$n.sig))
lines(apply(Pnull$Lambda, 2, FUN=quantile, probs=0.95))
points(Pnull$Lambda.orig[1:20], pch=16)

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

Для сравнения, давайте посмотрим на набор данных с неслучайным набором данных: iris

# iris dataset example
m <- iris[,1:4]
Pnull <- prcompNull(m, center = TRUE, scale=FALSE, nperm = 100)
Pnull$n.sig
boxplot(Pnull$Lambda, ylim=range(Pnull$Lambda, Pnull$Lambda.orig), outline=FALSE, col=8, border="grey50", log="y", main=paste("m (center=FALSE); n sig. =", Pnull$n.sig))
lines(apply(Pnull$Lambda, 2, FUN=quantile, probs=0.95))
points(Pnull$Lambda.orig[1:20], pch=16)

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

Здесь 1-е единственное значение является значимым и объясняет более 92% от общей дисперсии:

P <- prcomp(m, center = TRUE)
P$sdev^2 / sum(P$sdev^2)
# [1] 0.924618723 0.053066483 0.017102610 0.005212184
Марк в коробке
источник
+1. Пример набора данных Iris интересен, потому что, глядя на первые два компьютера (как, например, в вашем собственном посте здесь stats.stackexchange.com/a/88092 ), совершенно ясно, что второй действительно несет некоторый сигнал. Тест на перестановку (он же тасует) показывает, что только 1-й является «значительным». Понятно, что перетасовка имеет тенденцию недооценивать количество ПК: большая дисперсия первого реального ПК будет «распространяться» на перетасованные ПК и будет поднимать их все, начиная со второго. Можно разработать более чувствительные тесты, которые объясняют это, но это делается редко.
говорит амеба: восстанови Монику
@amoeba - Отличный комментарий. Я размышлял о «распространяющемся» эффекте уже некоторое время. Я полагаю, что тест перекрестной проверки может быть одним из наиболее важных, на которые вы ссылаетесь (например, ваш ответ здесь )? Было бы здорово, если бы вы могли предоставить пример / ссылку.
Марк в коробке
Я обычно предпочитаю использовать перекрестную проверку (основанную на ошибке реконструкции, согласно моему ответу здесь ), но я на самом деле не уверен, не страдает ли она от того же рода нечувствительности или нет. Возможно, имеет смысл попробовать это на наборе данных Iris. Что касается подходов, основанных на тасовании, я не знаю никаких ссылок для объяснения этого «распространения», я просто знаю некоторых людей, которые работали над этим недавно. Я думаю, что они хотели написать это в ближайшее время. Идея состоит в том, чтобы ввести некоторые коэффициенты уменьшения масштаба для дисперсий ПК с более высокой перетасовкой.
говорит амеба: восстанови монику
@amoeba - Спасибо за эту ссылку. Это многое объясняет для меня. Мне было особенно интересно увидеть, что перекрестная проверка в PCA использует методы, которые могут работать с наборами данных с пропущенными значениями. Я предпринял несколько попыток использовать этот подход, и (как вы заявляете) подход с перестановкой нулевой модели действительно имеет тенденцию недооценивать количество значимых ПК. Однако для набора данных радужной оболочки я последовательно возвращаю один компьютер для ошибки реконструкции. Интересно, учитывая то, что вы упомянули о сюжете. Может быть, если бы мы измеряли погрешность на основе предсказаний видов, результаты могли бы быть другими.
Марк в коробке
Из любопытства я попробовал это на данных радужной оболочки. На самом деле, я получаю два значимых ПК с методом перекрестной проверки. Я обновил свой связанный пост, пожалуйста, смотрите там.
говорит амеба: восстанови Монику