Freitag, 29. Mai 2009

Kombinationen tabellieren

Ausgangslage ist ein data.frame mit einer Zeile pro Element und n Indikatorvariablen. Es stellt sich die Frage nach den Häufigkeiten der Kombinationen der Indikatorvariablen.

d.frm <- data.frame(name=c("Franz", "Maria", "Claudine")
  , A=c(1,0,1), B=c(1,1,1), C=c(0,0,1), D=c(0,1,0))

Solution 1 (clumsy):

# Berechne die Summe der mit einer 2er-Potenz multiplizierten Indikatoren
d.frm$sum <- as.matrix(d.frm[,2:5]) %*% (2^(0:3))

# Erzeuge levels für eine Komb-Faktor
d.lvl <- expand.grid( c(0,"A"),c(0,"B"),c(0,"C"),c(0,"D") )

# Bilde eine neue Variable mit der Textbezeichnung der 2^n-Summe
d.frm$sum_x <- factor(d.frm$sum
  , levels=((d.lvl!=0)*1) %*% (2^(0:3))
  , labels=gsub( "0","", do.call( "paste", c( d.lvl, list(sep="") ))))

d.frm
......name A B C D sum sum_x
1 ...Franz 1 1 0 0 ..3 ...AB
2 ...Maria 0 1 0 1 .10 ...BD
3 Claudine 1 1 1 0 ..7 ..ABC

Solution 2 (smart):

d.frm$sum_xx <- apply( d.frm[,2:5], 1,
  function(x) paste(LETTERS[1:4][as.logical(x)], collapse="") )


Wenn einfach nur die Kombinationen gesucht sind, gibt's dafür die Bordmittel:

> combn( letters[1:4], 2 )
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] "a" "a" "a" "b" "b" "c"
[2,] "b" "c" "d" "c" "d" "d"

Oder auch interessant mit den Funktionen outer und lower.tri (pairwise):

m <- outer(x, x, paste, sep="-" )
m[!lower.tri(m, diag=TRUE) ]

[1] "a-b" "a-c" "b-c" "a-d" "b-d" "c-d"

Get all binary combinations
The idea is to get a vector with n 0s and n 1s, chop it into n parts of c(0,1) (this is a list), and use expand.grid:

n <- 4="4">
expand.grid(split(rep(c(0,1), each=n), 1:n))

Montag, 25. Mai 2009

Gruppenweise Auswertung

Erstaunlich umständlich ist die gruppenweise Selektion von bestimmten Elementen eines dataframes. Zum Beispiel soll gruppenweise das erste Element nach einer vorgegebenen Sortierung zurückgegeben werden:

d.frm <- data.frame(
name=c("Max","Max","Max","Max","Max","Moritz","Moritz","Moritz")
,typ=c("rot","blau","grün","blau","grün","rot","rot","blau")
,anz=c(5,4,5,8,3,2,9,1) )

d.frm <- d.frm[ order(d.frm$name, -d.frm$anz),]
d.frm
....name .typ anz
4 ...Max blau ..8
1 ...Max .rot ..5
3 ...Max grün ..5
2 ...Max blau ..4
5 ...Max grün ..3
7 Moritz .rot ..9
6 Moritz .rot ..2
8 Moritz blau ..1


d.frm[ tapply( rownames(d.frm), d.frm$name, head, n=1), ]
. ..name. typ.anz
4....Max.blau...8
7 Moritz..rot...9


Noch einfacher ist allerdings:
d.frm <- d.frm[ order(d.frm$name, -d.frm$anz),]
d.frm[ !duplicated(d.frm$name),]

Wenn der zweite Wert gesucht wäre, ginge dies mit der Index-Funktion "[":
d.frm[ tapply( rownames(d.frm), d.frm$name, "[", 2),  ]