Заполните пропущенные значения в матрице значениями из разных строк в этой матрице в R

#r #matrix

#r #матрица

Вопрос:

У меня есть матрица с нуклеотидными последовательностями (содержащими NAs) в строках, как показано здесь:

n.mat

 samp1 <- c("a","c","a",NA,"t","c")
samp2 <- c("a","c","t","t",NA,"a")
samp3 <- c("a","g","g","c","a","c")
samp4 <- c("a","g",NA,"g","g", NA)
samp5<- c(NA, "g","g","g","t","g")

n.mat <- rbind(samp1,samp2,samp3,samp4,samp5)

      [,1] [,2] [,3] [,4] [,5] [,6]
samp1 "a"  "c"  "a"   NA  "t"  "c" 
samp2 "a"  "c"  "t"  "t"   NA  "a" 
samp3 "a"  "g"  "g"  "c"  "a"  "a" 
samp4 "a"  "g"   NA  "g"  "g"   NA 
samp5  NA  "g"  "g"  "g"  "t"  "g" 
  

У меня также есть фрейм данных с двумя столбцами, содержащими имена последовательностей:

df

 df <- data.frame(
  X1 = c("samp1", "samp2", "samp3", "samp4", "samp5"),
  X2 = c("samp2", "samp5", "samp1", "samp3", "samp2"))

          X1       X2
1      samp1    samp2
2      samp2    samp5
3      samp3    samp1
4      samp4    samp3
5      samp5    samp2
  

Я хотел бы заполнить пробелы строки в матрице нуклеотидами / значениями из другой строки в матрице, обозначенной df$X2 столбцом во фрейме данных.

Так, например: samp1 в матрице есть NA в своей строке в четвертом столбце. Поэтому я хотел бы взять строку из того же столбца samp2 (обозначается фреймом данных в столбце X2 ). Поскольку samp2 я хотел бы заполнить NA , взяв строку из samp5 (обозначенную фреймом данных в столбце X2 ). Если NA в строке, в которой она находится, нет samp3 , то ничего не делайте. Если в строке их два NAs (как в samp4 ), то я хотел бы взять обе строки из samp3 обоих столбцов.

Я попробовал следующий код:

 replace.na <- function(n.mat,val) {
  i <- is.na(n.mat)
  j <- which(i)
  k <- which(!i)
  n.mat[j[j > k[length(k)]]] <- val
  n.mat
}

n.mat[,-1] <- t(apply(matrix[,-1],1,replace.na)) 
  

Но я не совсем уверен, как включить df таблицу для замены NAs .

Ответ №1:

Вот очень компактный код, который я объясню (и он предполагает либо использование rv4.x, либо создание фрейма данных ‘df’ с stringsAsFactors=FALSE помощью):

 n.mat[ is.na(n.mat) ] <-  n.mat[df[['X2']],][ is.na(n.mat)]

n.mat
#------
      [,1] [,2] [,3] [,4] [,5] [,6]
samp1 "a"  "c"  "a"  "t"  "t"  "c" 
samp2 "a"  "c"  "t"  "t"  "t"  "a" 
samp3 "a"  "g"  "g"  "c"  "a"  "a" 
samp4 "a"  "g"  "g"  "g"  "g"  "a" 
samp5 "a"  "g"  "g"  "g"  "t"  "g" 
  

is.na(.n.mat) Возвращает логическую матрицу того же измерения, что и n.mat. Он используется в качестве индекса с обеих сторон присваивания, но в правой части присваивания выполняется выбор из матрицы, строки которой переставлены в соответствии с порядком «замещающих строк», который вы указали df . Если бы столбец ‘X1’ не был в том же порядке, что и целевая матрица, вам нужно было бы изменить порядок этого столбца с помощью order вызова, но здесь это не понадобилось.

  df <- read.table(text= 'X1       X2
 1      samp1    samp2
 2      samp2    samp5
 3      samp3    samp1
 4      samp4    samp3
 5      samp5    samp2', header=TRUE, stringsAsFactors=FALSE)
  

Обратите внимание на stringsAsFactors=FALSE . Я думаю, что моя неспособность использовать это (поскольку я все еще на R 3.6) означала, что у меня были коэффициенты в столбце X2.

Другой способ сделать это — создать индекс из двух столбцов позиций NA с параметром arr.idx, установленным в TRUE:

  pos <- which(is.na(n.mat),arr.ind=TRUE)

> pos
      row col
samp5   5   1
samp4   4   3
samp1   1   4
samp2   2   5
samp4   4   6
  

Затем вы можете индексировать с помощью этой матрицы из 2 столбцов:

  n.mat[pos] <- n.mat[ df[['X2']] ,][pos]

> n.mat
      [,1] [,2] [,3] [,4] [,5] [,6]
samp1 "a"  "c"  "a"  "t"  "t"  "c" 
samp2 "a"  "c"  "t"  "t"  "t"  "a" 
samp3 "a"  "g"  "g"  "c"  "a"  "a" 
samp4 "a"  "g"  "g"  "g"  "g"  "a" 
samp5 "a"  "g"  "g"  "g"  "t"  "g" 
  

Индексация матрицы R может привести к некоторым очень компактным решениям подобных проблем. Вам следует прочитать страницу ?'[' справки для получения более подробной информации и примеров. Время, потраченное на эти усилия, окупится многократно, если вы продолжите использовать R. Я уверен, что уже прочитал это 10 или 20 раз.

Reprex:

 n.mat <- matrix( scan(text = 'samp1 "a"  "c"  "a"  "NA" "t"  "c" 
 samp2 "a"  "c"  "t"  "t"  "NA" "a" 
 samp3 "a"  "g"  "g"  "c"  "a"  "a" 
 samp4 "a"  "g"  "NA" "g"  "g"  "NA" 
 samp5 "NA" "g"  "g"  "g"  "t"  "g" ', what=""), nrow=5, byrow=TRUE)

 n.mat <- matrix(n.mat[ ,-1], nrow=5, dimnames=list(n.mat[,1], NULL))

df <- read.table(text= 'X1       X2
 1      samp1    samp2
 2      samp2    samp5
 3      samp3    samp1
 4      samp4    samp3
 5      samp5    samp2', header=TRUE, stringsAsFactors=FALSE)
  

Комментарии:

1. Привет, большое спасибо, я думаю, что ваша идея была очень полезной, и она работает довольно хорошо, если нет повторений. Но я думаю NA , что данные из второй строки и 5-го столбца матрицы были преобразованы неправильно. Это должно быть a t . Я также проверял разные варианты расположения NAs , и тогда он не будет преобразовывать каждый NA . Может быть, у вас есть другой вариант?

2. Код был правильным (я думаю), но я подозреваю, что мы оба использовали R 3.6 или ниже и принимали значение по умолчанию stringsAsFactors для создания data.frame. Не должно быть проблем с несколькими NAS в строке. Может возникнуть проблема, если в таблице замены df не было записи для конкретной строки матрицы n.mat. В этом случае вы должны вставить заполнитель со строкой, ссылающейся на саму себя. например 3 sampx sampx

Ответ №2:

Вы могли бы попробовать что-то вроде этого ниже. Обратите внимание, что результат немного отличается, но я скопировал / вставил ваш код для создания вашей матрицы (см. samp3 Столбец 6).

 t(sapply(rownames(n.mat), function(x) {
  na_cols <- is.na(n.mat[x, ])
  n.mat[x, na_cols] <- n.mat[df[df$X1 == x, "X2"], na_cols]
  n.mat[x, ]
}))
  

Вывод

       [,1] [,2] [,3] [,4] [,5] [,6]
samp1 "a"  "c"  "a"  "t"  "t"  "c" 
samp2 "a"  "c"  "t"  "t"  "t"  "a" 
samp3 "a"  "g"  "g"  "c"  "a"  "c" 
samp4 "a"  "g"  "g"  "g"  "g"  "c" 
samp5 "a"  "g"  "g"  "g"  "t"  "g" 
  

Данные

 n.mat <- structure(c("a", "a", "a", "a", NA, "c", "c", "g", "g", "g", 
"a", "t", "g", NA, "g", NA, "t", "c", "g", "g", "t", NA, "a", 
"g", "t", "c", "a", "c", NA, "g"), .Dim = 5:6, .Dimnames = list(
    c("samp1", "samp2", "samp3", "samp4", "samp5"), NULL))
  

Комментарии:

1. Проверьте свой результат и проверьте, является ли ваш df $ X2 фактором.

2. Мой df$X2 не был фактором, просто вектор символов (я использую R 4.0.2 и, возможно, привыкаю stringsAsFactors к FALSE умолчанию)… Кстати, мне нравится ваш компактный код / ответ…

3. Я получаю разные результаты. Посмотрите на столбец 6, строки 3 и 4.

4. Хм … я получил те же результаты, что и ваш ответ. Интересно, может ли это быть связано с различием в n.mat данных. Данные примера OP, возможно, изменились — samp3 вектор заканчивается на «c» — но после rbind n.mat того, как матрица имеет строку samp3 col 6 как «a». Я добавлю свои данные примера к своему ответу (хотя и испытываю желание удалить, не уверен, насколько это полезно).

5. Вы правы. OP изменил пример и не сообщил нам. Я использовал исходную проблему.