2012-10-25 3 views
7

Meine Frage ist: Ich habe einen Datenrahmen mit einigen Faktorvariablen. Ich möchte nun diesem Datenrahmen einen neuen Vektor zuweisen, der für jede Teilmenge dieser Faktorvariablen einen Index erstellt.Wie wird ein Zähler einer bestimmten Teilmenge eines data.frames zugewiesen, der durch eine Faktorkombination definiert ist?

data <-data.frame(fac1=factor(rep(1:2,5)), fac2=sample(letters[1:3],10,rep=T)) 

Gibt mir so etwas wie:

 fac1 fac2 
    1  1 a 
    2  2 c 
    3  1 b 
    4  2 a 
    5  1 c 
    6  2 b 
    7  1 a 
    8  2 a 
    9  1 b 
    10 2 c 

Und was ich will, ist eine Kombination Zähler, der das Auftreten eines jeden Faktorkombination zählt. Gefallen Sie diese

 fac1 fac2 counter 
    1  1 a  1 
    2  2 c  1 
    3  1 b  1 
    4  2 a  1 
    5  1 c  1 
    6  2 b  1 
    7  1 a  2 
    8  2 a  2 
    9  1 b  2 
    10 1 a  3 

Bisher dachte ich über tapply mit dem Zähler über alle Faktor-Kombinationen zu erhalten, die

counter <-tapply(data$fac1, list(data$fac1,data$fac2), function(x) 1:length(x)) 

gut funktioniert Aber ich weiß nicht, wie ich die Zählerliste zuordnen kann (zB nicht gelistet) zu den Kombinationen im Datenrahmen ohne ineffiziente Schleifen zu verwenden :)

+0

es um sein muss oder wollen Sie einfach nur net zählt? Wenn Sie nur zählen möchten, kann die Tabelle (Einfügen (Daten $ fac1, data $ fac2, sep = "-")) hilfreich sein. – screechOwl

+0

Hallo! Innerhalb jeder fac1 x fac2-Kombination spielt die Reihenfolge eine Rolle. (Man kann sich das so vorstellen wie mal eine Person "fac1" den Buchstaben "fac2" sah) – JBJ

+0

Du könntest die gleiche Grundstrategie verwenden, aber von 'tapply' auf' ddply' von ** plyr ** umschalten, oder falls du Daten sind riesig und Leistung ist ein Problem, "data.table". – joran

Antwort

6

Dies ist eine Aufgabe für die ave() Funktion:

# Use set.seed for reproducible examples 
# when random number generation is involved 
set.seed(1) 
myDF <- data.frame(fac1 = factor(rep(1:2, 7)), 
        fac2 = sample(letters[1:3], 14, replace = TRUE), 
        stringsAsFactors=FALSE) 
myDF$counter <- ave(myDF$fac2, myDF$fac1, myDF$fac2, FUN = seq_along) 
myDF 
# fac1 fac2 counter 
# 1  1 a  1 
# 2  2 b  1 
# 3  1 b  1 
# 4  2 c  1 
# 5  1 a  2 
# 6  2 c  2 
# 7  1 c  1 
# 8  2 b  2 
# 9  1 b  2 
# 10 2 a  1 
# 11 1 a  3 
# 12 2 a  2 
# 13 1 c  2 
# 14 2 b  3 

Beachten Sie die Verwendung von stringsAsFactors=FALSE im data.frame() Schritt. Wenn Sie das nicht haben, können Sie immer noch die Ausgabe mit erhalten: myDF$counter <- ave(as.character(myDF$fac2), myDF$fac1, myDF$fac2, FUN = seq_along).

+0

Es ist ganz sicher, + 1 –

+0

Große Antwort !!!! +1 –

+0

Vergleichte mirdwab und meine Lösung in Bezug auf Effizienz (konnte @mplourde nicht zur Arbeit) und der Mrdwab ist doppelt so schnell. Für 1000000 Zeilen ist es 1,693 vs. 3,382 Sekunden – vaettchen

0

Dies ist eine Basis-R-Methode, die (explizite) Schleifen vermeidet.

data$counter <- with(data, { 
    inter <- as.character(interaction(fac1, fac2)) 
    names(inter) <- seq_along(inter) 
    inter.ordered <- inter[order(inter)] 
    counter <- with(rle(inter.ordered), unlist(sapply(lengths, sequence))) 
    counter[match(names(inter), names(inter.ordered))] 
}) 
0

Hier eine Variante mit etwas Looping (Ich habe Ihre Variable „x“, da „data“ umbenannt verwendet wird sonst):

x <-data.frame(fac1=rep(1:2,5), fac2=sample(letters[1:3],10,rep=T)) 
x$fac3 <- paste(x$fac1, x$fac2, sep="") 
x$ctr <- 1 
y <- table(x$fac3) 
for(i in 1 : length(rownames(y))) 
    x$ctr[x$fac3 == rownames(y)[i]] <- 1:length(x$ctr[x$fac3 == rownames(y)[i]]) 
x <- x[-3] 

Keine Ahnung, ob dies über eine große data.frame effizient Aber es funktioniert!

4

A data.table Lösung

library(data.table) 
DT <- data.table(data) 
DT[, counter := seq_len(.N), by = list(fac1, fac2)] 
Verwandte Themen