Две петли в списке с NA - R - PullRequest
1 голос
/ 30 марта 2020

Предположим, у меня есть фрейм данных (df), где каждая строка заканчивается NA.

    > df
    #      [,1] [,2] [,3] [,4] [,5]
    # [1,]    1    7    9    4   NA
    # [2,]    3    6   NA   NA   NA
    # [3,]    1    6    6    4    3
    # [4,]    7    7   NA   NA   NA
    # [5,]    4    3    1    8   NA

Я создал список с каждой строкой без NA * S

nn <-c()
for (i in 1:nrow(df)){
  nn[[i]]<-t(na.omit(t(df[i,])))
}

Например, nn [[1]] = {1,7,9,4}.

Теперь я хочу определить расстояние между каждой парой строк, но только с учетом минимального количества наблюдений пары. Например, в первом ряду 4 наблюдения, а в третьем - 5 наблюдений. Таким образом, расстояние между первым и третьим рядом будет учитывать только первые 4 наблюдения. Я сделал этот код, который работает! Но это не автомат c:

i <- 1
dd <- c()
for (j in 1:nrow(df)){
  dd[j] <- dist(as.data.frame(rbind(nn[[i]][1:min(lengths(nn[i]),lengths(nn[j]))],nn[[j]][1:min(lengths(nn[i]),lengths(nn[j]))])))
}
dd1 <- dd

С i<-1 я вычислил расстояние между строкой 1 и остальными строками. И R сохраняет dd1 с этими расстояниями. Если я сделаю i<-2 и dd2 <- dd, я получу то же самое для второго ряда и т. Д.

Реальный набор данных, с которым я работаю, намного больше, и я хочу сделать это автоматически. Я попытался изменить значение от 1 до nrow (df) и сделать что-то вроде dd [i, j], но не работает. Может ли кто-нибудь помочь мне сделать это автоматически?

1 Ответ

1 голос
/ 30 марта 2020

Не следует удалять значения NA, они помогут при расчете расстояний.

Итак, начнем с ваших исходных данных:

df
  V1 V2 V3 V4 V5
1  1  7  9  4 NA
2  3  6 NA NA NA
3  1  6  6  4  3
4  7  7 NA NA NA
5  4  3  1  8 NA

Мы пытаемся вычислить расстояния между всеми строки, использующие dist() в одной go:

dst <- as.matrix(dist(df, diag=TRUE, upper=TRUE))
dst
          1        2        3        4         5
1  0.000000 3.535534 3.535534 9.486833 11.456439
2  3.535534 0.000000 3.162278 6.519202  5.000000
3  3.535534 3.162278 0.000000 9.617692  8.587782
4  9.486833 6.519202 9.617692 0.000000  7.905694
5 11.456439 5.000000 8.587782 7.905694  0.000000

Теперь эти значения немного странные, не уверен, что это то, что вы ищете. Читая help(dist) мы видим этот бит:

Если при вычислении евклидова, манхэттенского, канберрского или минковского расстояния некоторые столбцы исключаются, сумма масштабируется пропорционально количеству используемых столбцов. Если все пары исключаются при расчете определенного расстояния, значение равно «NA».

То, что это говорит - если ваши данные имеют NA, расстояния масштабируются, так что отсутствующие значения также добавляют на расстояние. Это делает расстояния сопоставимыми по размеру, несмотря на то, что некоторые элементы имеют значения NA.

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

Функция видит, что для некоторого определенного c расстояния использовались 2 из 5 столбцов, а остальные были NA. Он умножает сумму на расстоянии на 5/2, а затем принимает квадратное root значение (согласно евклидовой формуле) ios, 2-й - взять квадрат root значений этих крыс ios, а 3-й - перенастроить.

Начнем с того, что для каждого расстояния получаем количество элементов NA, использованных для их вычисления:

nas <- outer(rowSums(is.na(df)), rowSums(is.na(df)), FUN=pmax)
nas
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    3    1    3    1
[2,]    3    3    3    3    3
[3,]    1    3    0    3    1
[4,]    3    3    3    3    3
[5,]    1    3    1    3    1

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

frac <- (ncol(df)-nas) / ncol(df)
frac
     [,1] [,2] [,3] [,4] [,5]
[1,]  0.8  0.4  0.8  0.4  0.8
[2,]  0.4  0.4  0.4  0.4  0.4
[3,]  0.8  0.4  1.0  0.4  0.8
[4,]  0.4  0.4  0.4  0.4  0.4
[5,]  0.8  0.4  0.8  0.4  0.8

Мы видим, например, что для пары 1-2 у нас было 3 пропущенные значения и 2 доступных значения. Таким образом, доступные составляли 40% от целого.

Далее мы берем квадратные корни этих крыс ios и умножаем их на расстояния, которые мы получили (эти скорректированные расстояния), чтобы восстановить это масштабирование:

res <- dst * sqrt(frac)
res
          1        2        3        4         5
1  0.000000 2.236068 3.162278 6.000000 10.246951
2  2.236068 0.000000 2.000000 4.123106  3.162278
3  3.162278 2.000000 0.000000 6.082763  7.681146
4  6.000000 4.123106 6.082763 0.000000  5.000000
5 10.246951 3.162278 7.681146 5.000000  0.000000

И это ваш результат. Итак, подведем итог:

dst  <- as.matrix(dist(df, diag=TRUE, upper=TRUE))
nas  <- outer(rowSums(is.na(df)), rowSums(is.na(df)), FUN=pmax)
frac <- (ncol(df)-nas) / ncol(df)
res  <- dst * sqrt(frac)
...