web-dev-qa-db-fra.com

Combinez la colonne pour supprimer les NA

J'ai quelques colonnes dans R et pour chaque ligne, il n'y aura jamais qu'une valeur dans l'une d'entre elles, le reste sera constitué de NA. Je veux les combiner dans une colonne avec la valeur non-NA. Est-ce que quelqu'un connaît un moyen facile de le faire? Par exemple, je pourrais avoir comme suit:

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))

Donc j'aurais

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

Et je voudrais obtenir

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

Les noms des colonnes contenant NA changent en fonction du code précédemment dans la requête. Par conséquent, je ne pourrai pas appeler les noms de colonne explicitement, mais j'ai les noms des colonnes contenant les NA stockés sous forme de vecteur, par exemple. Dans cet exemple, cols <- c('x','y','z'), alors pourrait appeler les colonnes en utilisant data[, cols].

Toute aide serait appréciée.

Merci

27
user1165199

Vous pouvez utiliser unlist pour transformer les colonnes en un seul vecteur. na.omit peut ensuite être utilisé pour supprimer les NAs.

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
17
Sven Hohenstein

Une solution basée sur dplyr::coalesce pourrait être la suivante:

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 

Les données

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))
16
MKR

Voici une solution plus générale (mais encore plus simple) qui s'étend à tous les types de colonnes (facteurs, caractères, etc.) avec des NA non ordonnés. La stratégie consiste simplement à fusionner les valeurs non-NA d'autres colonnes dans votre colonne fusionnée en utilisant is.na pour l'indexation:

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

Notez que cela écrasera les valeurs existantes dans m s'il existe plusieurs valeurs non NA dans la même ligne. Si vous avez beaucoup de colonnes, vous pouvez automatiser cela en bouclant sur colnames(data).

11
Jonas Lindeløv

J'utiliserais rowSums() avec l'argument na.rm = TRUE:

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

qui donne:

> 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

Vous devez appeler la méthode directement (cbind.data.frame) car le premier argument ci-dessus n'est pas un cadre de données.

10
Gavin Simpson

Quelque chose comme ça ?

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

donne: 

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

max fonctionne aussi. Fonctionne également sur les vecteurs de chaînes.

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

Dans un lien connexe ( supprimer les NA en pâte () ), je présente une version de paste avec une option na.rm (avec le nom malheureux de paste5).

Avec cela le code devient

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

La sortie de paste5 est un caractère, ce qui fonctionne si vous avez des données de caractère, sinon vous devrez forcer le type que vous voulez.

0
JWilliman

Bien que ce ne soit pas le cas du PO, il semble que certaines personnes aiment l’approche basée sur les sommes, qu’en est-il de penser en mode et en mode, pour rendre la réponse plus universelle. Cette réponse correspond au titre, qui est ce que beaucoup de gens vont trouver.

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
0
Ferroao