Połącz kolumnę, aby usunąć NA

Mam kilka kolumn w R i dla każdego wiersza będzie tylko wartość w jednym z nich, reszta będzie NA. Chcę połączyć je w jedną kolumnę z wartością non-NA. Czy ktoś wie, jak łatwo to zrobić? Na przykład mogę mieć następujące:

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

Więc chciałbym

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

And I would to get

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

Nazwy kolumn zawierających NA zmieniają się w zależności od kodu wcześniej w zapytaniu, więc nie będę mógł wywołać kolumny nazwy jawnie, ale mam nazwy kolumn, które zawierają NA zapisane jako wektor np. w tym przykładzie cols <- c('x','y','z'), więc mogę wywołać kolumny za pomocą data[, cols].

Każda pomoc będzie mile widziana.

Dzięki

 52
Author: Gavin Simpson, 2013-01-28

10 answers

A dplyr::coalesce Rozwiązanie oparte może mieć postać:

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 

Dane

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))
 43
Author: MKR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-15 09:32:58

Możesz użyć unlist, aby zamienić kolumny w jeden wektor. Następnie, na.omit można użyć do usunięcia 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
 21
Author: Sven Hohenstein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-09 15:31:58

Oto bardziej ogólne (ale jeszcze prostsze) rozwiązanie, które obejmuje wszystkie typy kolumn (czynniki, znaki itp.) z nie-uporządkowanymi wartościami NA. strategia polega po prostu na połączeniu wartości nie-NA innych kolumn w scaloną kolumnę za pomocą is.na do indeksowania:

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

Zauważ, że to nadpisze istniejące wartości w m, jeśli w tym samym wierszu znajduje się kilka wartości innych niż NA. Jeśli masz dużo kolumn, możesz to zautomatyzować poprzez zapętlenie colnames(data).

 13
Author: Jonas Lindeløv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-18 12:24:51

Użyłbym rowSums() z argumentem na.rm = TRUE:

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

Co daje:

> 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

Musisz wywołać metodę bezpośrednio (cbind.data.frame), ponieważ pierwszy argument powyżej nie jest ramką danych.

 12
Author: Gavin Simpson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-28 14:02:59

Coś takiego ?

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

Daje:

  a mycol
1 A     1
2 B     2
3 C     3
4 D     4
5 E     5
 5
Author: juba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-28 13:57:21

Max też działa. Działa również na wektorach strun.

cbind(data[1], mycol=apply(data[-1], 1, max, na.rm=T))
 1
Author: drollix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-20 18:55:02

W powiązanym linku (wyłącz NAs w paste () ) przedstawiam wersję paste z opcją na.rm (z niefortunną nazwą paste5).

Tym kodem staje się

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

Wyjściem paste5 jest znak, który działa, jeśli masz dane znaków, w przeciwnym razie będziesz musiał wymuszać na żądanym typie.

 0
Author: JWilliman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:16

Choć nie jest to przypadek OP, wydaje się, że niektórzy ludzie lubią podejście oparte na sumach, co powiesz na myślenie w średnim i trybie, aby odpowiedź była bardziej uniwersalna. Ta odpowiedź pasuje do tytułu, który jest tym, co Wiele osób znajdzie.

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
Author: Ferroao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-25 19:47:10

Jedną z możliwości użycia dplyr i tidyr może być:

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

Tutaj przekształca dane z szerokiego na długi format, wyłączając pierwszą kolumnę z tej operacji i usuwając NAs.

 0
Author: tmfmnk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-03 21:13:09

Jeśli chcesz trzymać się Bazy,

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)
 0
Author: Bharadwaj A K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-15 12:56:01