2016-01-18 14 views
8

Ich habe eine data.frame mit vielen Spalten (~ 50). Einige von ihnen sind Zeichen, einige sind numerisch und 3 von denen verwende ich für die Gruppierung.R: zusammenfassen mehrere Spalte (numerisch, Zeichen) und entfernen NA

Ich muss:

  • entfernen NAs von numerischen Spalten
  • berechnen den Mittelwert von jeder der numerischen Spalten
  • extrahieren das erste Element der Zeichenspalten

Nehmen wir an, wir verwenden modifizierte Irisdaten wie folgt:

data(iris) 
iris$year <- rep(c(2000,3000),each=25) ## for grouping 
iris$color <- rep(c("red","green","blue"),each=50) ## character column 
iris[1,] <- NA ## introducing NAs 

Ich habe ~ 50 Spalten insgesamt, numerische und Zeichen zusammen gemischt. Ich habe versucht worden, so etwas wie:

giris <- group_by(iris, Species, year) 
cls <- unlist(sapply(giris, class)) ## find out classes 
action <- ifelse(cls == "numeric", "mean", "first") 
action <- paste(action) 
summarise_each(giris, action) 

Was ich erhalte, ist für alle Spalten in einer Gruppe von Spalten mit den ersten Werten in jeweiliger Gruppe gefolgt bedeutet. Und NAs werden nicht behandelt ... Was ist nicht genau das, was ich suche ...

Helfen Sie jemandem?

Antwort

9

Sie könnten versuchen, dies mit einem if/else in der funs von summarise_each:

iris %>% 
    group_by(Species, year) %>% 
    summarise_each(funs(if(is.numeric(.)) mean(., na.rm = TRUE) else first(.))) 

Da Sie einige der NA auch in Gruppierungsspalten haben Sie eine filter Aussage könnte hinzufügen:

iris %>% 
    filter(!is.na(Species) & !is.na(year)) %>% 
    group_by(Species, year) %>% 
    summarise_each(funs(if(is.numeric(.)) mean(., na.rm = TRUE) else first(.))) 
#Source: local data frame [6 x 7] 
#Groups: Species [?] 
# 
#  Species year Sepal.Length Sepal.Width Petal.Length Petal.Width color 
#  (fctr) (dbl)  (dbl)  (dbl)  (dbl)  (dbl) (chr) 
#1  setosa 2000  5.025 3.479167  1.4625  0.250 red 
#2  setosa 3000  4.984 3.376000  1.4640  0.244 red 
#3 versicolor 2000  6.012 2.776000  4.3120  1.344 green 
#4 versicolor 3000  5.860 2.764000  4.2080  1.308 green 
#5 virginica 2000  6.576 2.928000  5.6400  2.044 blue 
#6 virginica 3000  6.600 3.020000  5.4640  2.008 blue 

Um mögliche NAs in der Farbspalte (oder in nicht-numerischen Spalten) zu vermeiden, können Sie sie in first(na.omit(.)) ändern.


könnten Sie auch data.table versuchen:

library(data.table) 
setDT(iris) 
iris[!is.na(Species) & !is.na(year), lapply(.SD, function(x) { 
    if(is.numeric(x)) mean(x, na.rm = TRUE) else x[!is.na(x)][1L]}), 
    by = list(Species, year)] 
#  Species year Sepal.Length Sepal.Width Petal.Length Petal.Width color 
#1:  setosa 2000  5.025 3.479167  1.4625  0.250 red 
#2:  setosa 3000  4.984 3.376000  1.4640  0.244 red 
#3: versicolor 2000  6.012 2.776000  4.3120  1.344 green 
#4: versicolor 3000  5.860 2.764000  4.2080  1.308 green 
#5: virginica 2000  6.576 2.928000  5.6400  2.044 blue 
#6: virginica 3000  6.600 3.020000  5.4640  2.008 blue 
+0

Ich denke, Sie möchten 'na.omit()' oberhalb der 'group_by' hinzufügen, aber das ist der Kern der Frage. – JasonAizkalns

+0

@JasonAizkalns, ich denke nicht - das würde möglicherweise viele Zeilen entfernen, die aufbewahrt werden sollten. Aber ich stimme zu, dass ein 'Filter (! Is.na (Species) &! Is.na (year))' Sinn machen würde –

+0

Dies ist eine wirklich nette und (wichtigste) Arbeitslösung, die auch erlaubt, einen Blick darauf zu erhaschen geht unter die Haube von summarise_each. Ich bin wirklich, wirklich dankbar dafür, Doncendo :-). Denken Sie gleichzeitig, dass es einen Weg geben könnte, um es zu beschleunigen? – rpl

0

ich es versuchen:

1. Zum ersten Punkt, den Sie erwähnen, würde ich so etwas wie die folgenden tun (was isn 't notwendig für den zweiten Punkt):

na.omit(iris[ , which(sapply(iris, class) == "numeric")]) 

Um die zu trennen Spalten bei entweder numeric oder character, verwende ich die folgenden:

iris[ , which(sapply(iris, class) == "numeric")] 
iris[ , which(sapply(iris, class) == "character")] 

2. Die zweite Aufgabe, die ich die obige Zeile kombinieren mit colMeans:

colMeans(iris[ , which(sapply(iris, class) == "numeric")], na.rm = TRUE) 

3. das erste Element der Zeichenspalten zu extrahieren, können Sie einfach tun:

iris[1, which(sapply(iris, class) == "character")] 

Im genannten Fall für die Irisdaten, die erste Reihe ist komplett NA, auch die Zeichenspalten, so würde ich iterieren finden die erste nicht-NA-Reihe

k <- 1 
while(any(is.na(FirstCharacterElement <- iris[k, which(sapply(iris, class) == "character")]))){ 
    k <- k + 1 
} 

Seien Sie vorsichtig über den Klassenfaktor (die den Code in dem Fall der Irisdaten brechen, wo Spalte Spezies der Klasse Faktor ist und man vielleicht erwarten, dass es ein Zeichen sein Sie können dies mit sapply(iris, class) überprüfen und mit zB

ändern
iris$Species <- as.character(iris$Species) #or with similar column names 

Wenn Sie in den Daten lesen Sie den Parameter stringsAsFactors = FALSE von Funktionen read.table, read.csv oder ähnlich nennen können.