2015-11-30 13 views
8

Der Datensatz enthält drei Variablen: ID, Geschlecht und Grad (Faktor).Häufigkeit der Zeilen nach ID

mydata <- data.frame(id=c(1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,4), sex=c(1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1), 
        grade=c("a","b","c","d","e", "x","y","y","x", "q","q","q","q", "a", "a", "a", NA, "b")) 

Für jede ID, muss ich sehen, wie viele einzigartige Qualitäten wir haben, und dann eine neue Spalte (Aufruf N) schaffen die Klasse Frequenz aufzuzeichnen. Zum Beispiel haben wir für ID = 1 fünf eindeutige Werte für "Note", also N = 4; Für ID = 2 haben wir zwei eindeutige Werte für "Grade", also N = 2; für ID = 4 haben wir zwei eindeutige Werte für "Klasse" (ignorieren NA), so N = 2.

Der letzte Datensatz ist

mydata <- data.frame(id=c(1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,4), sex=c(1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1), 
        grade=c("a","b","c","d","e", "x","y","y","x", "q","q","q","q", "a", "a", "a", NA, "b")) 
mydata$N <- c(5,5,5,5,5,2,2,2,2,1,1,1,1,2,2,2,2,2) 
+0

eine verschachtelte 'for'-Schleife für jede eindeutige Note. – giraffehere

+4

For-Schleifen sind nicht die Antwort in R. Es sei denn, sie sind (was hier nicht der Fall ist). – Heroka

+0

Ich fragte mich auch, ob es möglich wäre, das * dplyr * zu verwenden und Zählungen für eindeutige Gruppen zu liefern. – Konrad

Antwort

9

Sie das Paket data.table verwenden:

library(data.table) 
setDT(mydata) 

#I have removed NA's, up to you how to count them 
mydata[,N_u:=length(unique(grade[!is.na(grade)])),by=id] 

Sehr kurz, lesbar und schnell. Es kann auch in der Basis-R erfolgen:

#lapply(split(grade,id),...: splits data into subsets by id 
#unlist: creates one vector out of multiple vectors 
#rep: makes sure each ID is repeated enough times 

mydata$N <- unlist(lapply(split(mydata$grade,mydata$id),function(x){ 
    rep(length(unique(x[!is.na(x)])),length(x)) 
} 
)) 

Weil es Diskussion darüber, was schneller ist, lassen Sie uns einige Benchmarking tun.

gegebenen Datensatz:

> test1 
Unit: milliseconds 
      expr  min  lq  mean median  uq  max neval cld 
length_unique 3.043186 3.161732 3.422327 3.286436 3.477854 10.627030 100 b 
     uniqueN 2.481761 2.615190 2.763192 2.738354 2.872809 3.985393 100 a 

Größere Datenmenge: (10000 Beobachtungen, 1000 ids)

> test2 
Unit: milliseconds 
      expr  min  lq  mean median  uq  max neval cld 
length_unique 11.84123 24.47122 37.09234 30.34923 47.55632 97.63648 100 a 
     uniqueN 25.83680 50.70009 73.78757 62.33655 97.33934 210.97743 100 b 
11

Mit this recent commit, uniqueN ein na.rm Argument hat, die wir wie folgt verwendet werden:

library(data.table) 
setDT(mydata)[, n := uniqueN(grade, na.rm=TRUE), by=id] 

Dies wird von der nächsten verfügbar sein stabile Version auf CRAN (v1.9.8). Alternativ können Sie auch die aktuelle devel Version (v1.9.7) installieren, indem Sie the instructions here ausprobieren, um es auszuprobieren.


Mit data.table Sie könnte dies wie folgt:

library(data.table) 
setDT(mydata)[, n := uniqueN(grade[!is.na(grade)]), by = id] 

oder:

setDT(mydata)[, n := uniqueN(na.omit(grade)), by = id] 

die gibt:

> mydata 
    id sex grade n 
1: 1 1  a 5 
2: 1 1  b 5 
3: 1 1  c 5 
4: 1 1  d 5 
5: 1 1  e 5 
6: 2 0  x 2 
7: 2 0  y 2 
8: 2 0  y 2 
9: 2 0  x 2 
10: 3 0  q 1 
11: 3 0  q 1 
12: 3 0  q 1 
13: 3 0  q 1 
14: 4 1  a 2 
15: 4 1  a 2 
16: 4 1  a 2 
17: 4 1 NA 2 
18: 4 1  b 2 
+0

@RichardScriven das gibt mir ein anderes Ergebnis – Jaap

+0

Ich bekomme das gleiche Ergebnis wie in Ihrer Antwort gezeigt, wenn Sie 'na.omit (grade)' verwenden. Was bekommst du? –

+0

@docendodiscimus Jetzt bekomme ich das gleiche Ergebnis. Wahrscheinlich gestern Abend einen Fehler gemacht. Option zur Antwort hinzugefügt. – Jaap

5

Sieht aus wie wir durchtrennen haben al Stimmen für data.table, aber man könnte auch die Basis R-Funktion ave() verwenden:

mydata$N <- ave(as.character(mydata$grade),mydata$id, 
       FUN = function(x) length(unique(x[!is.na(x)]))) 
+1

Eine andere Idee, mit der Basis, ist ' rowSums (Tabelle (mydata [c ("id", "grade")])> 0) [mydata $ id] ' –

4

Verwendung tapply und Lookup-Tabelle

mydata <- data.frame(id=c(1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,4), 
        sex=c(1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1), 
        grade=c("a","b","c","d","e", "x","y","y","x", "q", 
          "q","q","q", "a", "a", "a", NA, "b")) 
uniqN <- tapply(mydata$grade, mydata$id, function(x) sum(!is.na(unique(x)))) 
mydata$N <- uniqN[mydata$id] 
0

Hier ist ein dplyr Verfahren. Ich habe die Zusammenfassungstabelle für saubere Gründe getrennt gehalten.

library(dplyr) 

summary = 
    mydata %>% 
    distinct(id, grade) %>% 
    filter(grade %>% is.na %>% `!`) %>% 
    count(id) 

mydata %>% 
    left_join(summary) 
7

A dplyr Option, die Verwendung von dplyr::n_distinct und seinen na.rm -Argument macht:

Dies würde für eine `for` Schleife wie ein Job scheint, eine Iteration für jeden eindeutigen Wert ID tun und möglicherweise
library(dplyr) 
mydata %>% group_by(id) %>% mutate(N = n_distinct(grade, na.rm = TRUE)) 
#Source: local data frame [18 x 4] 
#Groups: id [4] 
# 
#  id sex grade  N 
# (dbl) (dbl) (fctr) (int) 
#1  1  1  a  5 
#2  1  1  b  5 
#3  1  1  c  5 
#4  1  1  d  5 
#5  1  1  e  5 
#6  2  0  x  2 
#7  2  0  y  2 
#8  2  0  y  2 
#9  2  0  x  2 
#10  3  0  q  1 
#11  3  0  q  1 
#12  3  0  q  1 
#13  3  0  q  1 
#14  4  1  a  2 
#15  4  1  a  2 
#16  4  1  a  2 
#17  4  1  NA  2 
#18  4  1  b  2 
Verwandte Themen