Подтвердить что ты не робот

Объединить столбец для удаления NA

У меня есть несколько столбцов в R, и для каждой строки будет только когда-либо значение в одном из них, остальные будут NA. Я хочу объединить их в один столбец с не-NA значением. Кто-нибудь знает простой способ сделать это. Например, я мог бы иметь следующее:

data <- data.frame('a' = c('A','B','C','D','E'),
                   'x' = c(1,2,NA,NA,NA),
                   'y' = c(NA,NA,3,NA,NA),
                   'z' = c(NA,NA,NA,4,5))

Итак, у меня было бы

'a' 'x' 'y' 'z'  
 A   1   NA  NA  
 B   2   NA  NA  
 C  NA   3   NA  
 D  NA   NA  4  
 E  NA   NA  5

И я хотел бы получить

 'a' 'mycol'  
  A   1  
  B   2  
  C   3  
  D   4  
  E   5  

Имена столбцов, содержащих NA, изменяются в зависимости от кода ранее в запросе, поэтому я не могу явно вызывать имена столбцов, но у меня есть имена столбцов, содержащие NA, хранящиеся в виде вектора, например. в этом примере cols <- c('x','y','z'), поэтому вы можете вызвать столбцы с помощью data[, cols].

Любая помощь будет оценена.

Спасибо

4b9b3361

Ответ 1

Решение на основе dplyr::coalesce может быть следующим:

data %>% mutate(mycol = coalesce(x,y,z)) %>%
         select(a, mycol)
#   a mycol
# 1 A     1
# 2 B     2
# 3 C     3
# 4 D     4
# 5 E     5 

Данные

data <- data.frame('a' = c('A','B','C','D','E'),
                 'x' = c(1,2,NA,NA,NA),
                 'y' = c(NA,NA,3,NA,NA),
                 'z' = c(NA,NA,NA,4,5))

Ответ 2

Вы можете использовать unlist, чтобы превратить столбцы в один вектор. Впоследствии na.omit можно использовать для удаления NA s.

cbind(data[1], mycol = na.omit(unlist(data[-1])))

   a mycol
x1 A     1
x2 B     2
y3 C     3
z4 D     4
z5 E     5

Ответ 3

Здесь более общее (но даже более простое) решение, которое распространяется на все типы столбцов (факторы, символы и т.д.) С неупорядоченными NA. Стратегия - просто объединить значения non-NA других столбцов в объединенный столбец, используя is.na для индексирования:

data$m = data$x  # your new merged column start with x
data$m[!is.na(data$y)] = data$y[!is.na(data$y)]  # merge with y
data$m[!is.na(data$z)] = data$z[!is.na(data$z)]  # merge with z

> data
  a  x  y  z m
1 A  1 NA NA 1
2 B  2 NA NA 2
3 C NA  3 NA 3
4 D NA NA  4 4
5 E NA NA  5 5

Обратите внимание, что это будет перезаписывать существующие значения в m, если в одной строке есть несколько значений, отличных от NA. Если у вас много столбцов, вы можете автоматизировать это, перейдя через colnames(data).

Ответ 4

Я бы использовал rowSums() с аргументом na.rm = TRUE:

cbind.data.frame(a=data$a, mycol = rowSums(data[, -1], na.rm = TRUE))

который дает:

> cbind.data.frame(a=data$a, mycol = rowSums(data[, -1], na.rm = TRUE))
  a mycol
1 A     1
2 B     2
3 C     3
4 D     4
5 E     5

Вы должны вызвать метод напрямую (cbind.data.frame), поскольку первый приведенный выше аргумент не является фреймом данных.

Ответ 5

Что-то вроде этого?

data.frame(a=data$a, mycol=apply(data[,-1],1,sum,na.rm=TRUE))

дает:

  a mycol
1 A     1
2 B     2
3 C     3
4 D     4
5 E     5

Ответ 6

max работает тоже. Также работает над векторами строк.

cbind(data[1], mycol=apply(data[-1], 1, max, na.rm=T))

Ответ 7

В связанной ссылке (подавить NA в пасте()) Я представляю версию paste с опцией na.rm (с неудачным именем paste5).

При этом код становится

cols <- c("x", "y", "z")
cbind.data.frame(a = data$a, mycol = paste2(data[, cols], na.rm = TRUE))

Вывод paste5 - это символ, который работает, если у вас есть данные символа, иначе вам нужно будет принуждать к типу, который вы хотите.

Ответ 8

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

data <- data.frame('a' = c('A','B','C','D','E'),
                   'x' = c(1,2,NA,NA,9),
                   'y' = c(NA,6,3,NA,5),
                   'z' = c(NA,NA,NA,4,5))

splitdf<-split(data[,c(2:4)], seq(nrow(data[,c(2:4)])))

data$mean<-unlist(lapply(splitdf, function(x)  mean(unlist(x), na.rm=T) ) )
data$mode<-unlist(lapply(splitdf, function(x)  {
  tab <- tabulate(match(x, na.omit(unique(unlist(x) )))); 
                  paste(na.omit(unique(unlist(x) ))[tab == max(tab) ], collapse = ", " )}) )

data
  a  x  y  z     mean mode
1 A  1 NA NA 1.000000    1
2 B  2  6 NA 4.000000 2, 6
3 C NA  3 NA 3.000000    3
4 D NA NA  4 4.000000    4
5 E  9  5  5 6.333333    5

Ответ 9

Одна из возможностей использования dplyr и tidyr может быть:

data %>%
 gather(variables, mycol, -1, na.rm = TRUE) %>%
 select(-variables)

   a mycol
1  A     1
2  B     2
8  C     3
14 D     4
15 E     5

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

Ответ 10

Если вы хотите придерживаться базы,

data <- data.frame('a' = c('A','B','C','D','E'),'x' = c(1,2,NA,NA,NA),'y' = c(NA,NA,3,NA,NA),'z' = c(NA,NA,NA,4,5))
data[is.na(data)]<-","
data$mycol<-paste0(data$x,data$y,data$z)
data$mycol <- gsub(',','',data$mycol)