Как переставить 2D данные, чтобы получить заданную корреляцию?

9

У меня есть следующий простой набор данных с двумя непрерывными переменными; то есть:

d = data.frame(x=runif(100,0,100),y = runif(100,0,100))
plot(d$x,d$y)
abline(lm(y~x,d), col="red")
cor(d$x,d$y) # = 0.2135273

Базовое распределение

Мне нужно переставить данные таким образом, чтобы корреляция между переменными составляла ~ 0,6. Мне нужно, чтобы средства и другая описательная статистика (sd, min, max и т. Д.) Обеих переменных были постоянными.

Я знаю, что можно сделать практически любую корреляцию с данными данными, т.е.

d2 = with(d,data.frame(x=sort(x),y=sort(y)))
plot(d2$x,d2$y)
abline(lm(y~x,d2), col="red")
cor(d2$x,d2$y) # i.e. 0.9965585

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

Если я попытаюсь использовать sampleфункцию для этой задачи:

cor.results = c()
for(i in 1:1000){
    set.seed(i)
    d3 = with(d,data.frame(x=sample(x),y=sample(y)))
    cor.results =  c(cor.results,cor(d3$x,d3$y))
}

Я получаю довольно широкий спектр корреляций:

> summary(cor.results)
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
-0.281600 -0.038330 -0.002498 -0.001506  0.034380  0.288800

но этот диапазон зависит от количества строк во фрейме данных и уменьшается с увеличением размера.

> d = data.frame(x=runif(1000,0,100),y = runif(1000,0,100))
> cor.results = c()
> for(i in 1:1000){
+ set.seed(i)
+ d3 = with(d,data.frame(x=sample(x),y=sample(y)))
+ cor.results =  c(cor.results,cor(d3$x,d3$y))
+ }
> summary(cor.results)
      Min.    1st Qu.     Median       Mean    3rd Qu.       Max. 
-0.1030000 -0.0231300 -0.0005248 -0.0005547  0.0207000  0.1095000

Мой вопрос:

Как переставить такой набор данных, чтобы получить данную корреляцию (т. Е. 0,7)? (Будет также хорошо, если метод уберет зависимость от размера набора данных)

Юрий Петровский
источник

Ответы:

6

Вот один из способов переупорядочения данных, основанный на генерации дополнительных случайных чисел.

xyxy

Сначала мы создаем фактический набор данных (как в вашем примере).

set.seed(1)
d <- data.frame(x = runif(100, 0, 100), y = runif(100, 0, 100))

cor(d$x, d$y)
# [1] 0.01703215

Теперь укажем корреляционную матрицу.

corr <- 0.7  # target correlation
corr_mat <- matrix(corr, ncol = 2, nrow = 2)
diag(corr_mat) <- 1
corr_mat
#      [,1] [,2]
# [1,]  1.0  0.7
# [2,]  0.7  1.0

μ=0σ=1mvrnormMASSempirical = TRUE

library(MASS)
mvdat <- mvrnorm(n = nrow(d), mu = c(0, 0), Sigma = corr_mat, empirical = TRUE)

cor(mvdat)
#      [,1] [,2]
# [1,]  1.0  0.7
# [2,]  0.7  1.0

Случайные данные идеально соответствуют указанной корреляции.

Далее мы вычисляем ранги случайных данных.

rx <- rank(mvdat[ , 1], ties.method = "first")
ry <- rank(mvdat[ , 2], ties.method = "first")

Чтобы использовать ранги для исходных данных d, мы должны отсортировать исходные данные.

dx_sorted <- sort(d$x)
dy_sorted <- sort(d$y)

Теперь мы можем использовать ранги, чтобы указать порядок отсортированных данных.

cor(dx_sorted[rx], dy_sorted[ry])
# [1] 0.6868986

Полученная корреляция не совсем соответствует указанной, но разница относительно невелика.

Здесь, dx_sorted[rx]и dy_sorted[ry]пересчитаны версии исходных данных в d.

Свен Хоэнштейн
источник
2
+1 Это довольно круто. Шаги: 1) сгенерировать нормальные данные с правильной корреляцией Пирсона, 2) сделать так, чтобы исходные данные и сгенерированные данные точно соответствовали ранговым корреляциям, 3) исходные данные теперь имеют примерно ту же корреляцию Пирсона. Почему это работает? Есть ли аналитический результат, который говорит, что это так? Ограничивающие неравенства, удерживающие различные меры корреляции близко друг к другу для распределений с хорошим поведением или что-то в этом роде?
Билл
1
@ Билл, я не могу объяснить подход аналитически. Это просто идея, которая пришла мне в голову. Тем не менее, вы суммировали шаги хорошо. Спасибо.
Свен Хоэнштейн
2

Для генерации двух равномерных распределений с заданной корреляцией будет работать алгоритм Ruscio & Kaczetow (2008). Они предоставляют R код . Затем вы можете преобразовать с помощью простой линейной функции, чтобы получить ваши минимальные, максимальные, средние значения и SD.

Алгоритм Русчио и Кацетова

XoYoX1Y1X1Y1X0Y0X1,Y1X2Y2

Обратите внимание, что это очень похоже на решение @Sven Hohenstein, за исключением того, что оно итеративное, поэтому промежуточная корреляция будет становиться все ближе и ближе к целевой корреляции, пока они не будут неразличимы. Также обратите внимание, что этот алгоритм может использоваться для генерации большой совокупности (например, N = 1 миллион), из которой можно выбирать меньшие выборки - это полезно, если вам нужна ошибка выборки.

Для соответствующего поста: корреляция и ненормальные распределения

Сохранение описательной статистики

Нет гарантии, что алгоритм выдаст точно такие же описания. Тем не менее, поскольку среднее значение равномерного распределения и SD определяются его минимальным и максимальным значениями, вы можете просто настроить минимальное и максимальное значения, чтобы все исправить.

XgYgXfYfXY

Xf=(Xgmin(X))(max(X)min(x))/(max(Xg)min(Xg))

Yf

Ссылка:

Ruscio, J. & Kaczetow, W. (2008). Моделирование многомерных ненормальных данных с использованием итерационного алгоритма. Многомерное поведенческое исследование, 43, 355–381. DOI: 10,1080 / 00273170802285693

Энтони
источник
1

Я предполагаю, что когда вы говорите «ресамплировать», вы имеете в виду «симулировать», что является более общим. Ниже приведен самый краткий способ, которым я знаю, для моделирования нормальных, двумерных данных с заданной корреляцией. Подставьте свои собственные желаемые значения для r и n.

r = .6
n = 1000
x = rnorm(n) 
z = rnorm(n) 
y = (r/(1-r^2)^.5)*x + z

cor(x,y)
plot(x,y)
abline(lm(y~x), col="red")
rolando2
источник
3
Нет, я действительно имею в виду «ресамплирование». Мне нужно сохранить средства и другую описательную статистику (sd, min, max) обеих переменных постоянными. Обновил вопрос.
Юрий Петровский