2012-04-13 7 views
4

Ich muss die folgende Funktion implementieren (idealerweise in R oder SQL): gegeben zwei Datenrahmen (haben eine Spalte für userid und der Rest der Spalten sind boolean Attribute (sie sind nur erlaubt, Nullen oder 1)) Ich brauche um einen neuen Datenrahmen mit zwei Spalten (Benutzer-ID und Anzahl) zurückzugeben, wobei Anzahl die Anzahl der Übereinstimmungen für Nullen und Einsen für jeden Benutzer in beiden Tabellen ist. Ein Benutzer F könnte in beiden Datenrahmen auftreten oder er könnte in nur einem auftreten. In diesem letzten Fall muss ich NA für diese Benutzeranzahl zurückgeben. Ich schreibe ein Beispiel:Wie würden Sie diese Aufgabe mit SQL oder R-Bibliothek sqldf tun?

DF1 
ID c1 c2 c3 c4 c5 
1 0 1 0 1 1 
10 1 0 1 0 0 
5 0 1 1 1 0 
20 1 1 0 0 1 
3 1 1 0 0 1 
6 0 0 1 1 1 
71 1 0 1 0 0 
15 0 1 1 1 0 
80 0 0 0 1 0 

DF2 
ID c1 c2 c3 c4 c5 
5 1 0 1 1 0 
6 0 1 0 0 1 
15 1 0 0 1 1 
80 1 1 1 0 0 
78 1 1 1 0 0 
98 0 0 1 1 1 
1 0 1 0 0 1 
2 1 0 0 1 1 
9 0 0 0 1 0 

Meine Funktion so etwas wie diese zurückgeben muss: (das folgende ist eine Teilmenge)

DF_Return 
ID Count 
1 4 
2 NA 
80 1 
20 NA 
    . 
    . 
    . 

Können Sie mir geben Anregungen dies durchzuführen? Ich bin nicht so Experte in SQL.

Ich lege die Codes in R, um das Experiment zu generieren, das ich oben verwendete.

id1=c(1,10,5,20,3,6,71,15,80) 
c1=c(0,1,0,1,1,0,1,0,0) 
c2=c(1,0,1,1,1,0,0,1,0) 
c3=c(0,1,1,0,0,1,1,1,0) 
c4=c(1,0,1,0,0,1,0,1,1) 
c5=c(1,0,0,1,1,1,0,0,0) 
DF1=data.frame(ID=id1,c1=c1,c2=c2,c3=c3,c4=c4,c5=c5) 
DF2=data.frame(ID=c(5,6,15,80,78,98,1,2,9),c1=c2,c2=c1,c3=c5,c4=c4,c5=c3) 

Vielen Dank im Voraus. Beste Grüße!

+0

Welche DBMS verwenden Sie? PostgreSQL? Orakel? DB2? .. –

+0

Hallo, ich benutze Microsoft SQL Server 2005! Danke – Nestorghh

Antwort

3

Hier ist ein Ansatz für Sie. Der erste Code codiert die zu vergleichenden Spalten, während der andere allgemeiner und agnostischer ist als die Anzahl der Spalten DF1 und DF2:

#Merge together using ALL = TRUE for equivlent of outer join 
DF3 <- merge(DF1, DF2, by = "ID", all = TRUE, suffixes= c(".1", ".2")) 
#Calculate the rowSums where the same columns match 
out1 <- data.frame(ID = DF3[, 1], count = rowSums(DF3[, 2:6] == DF3[, 7:ncol(DF3)])) 

#Approach that is agnostic to the number of columns you have 
library(reshape2) 
library(plyr) 
DF3.m <- melt(DF3, id.vars = 1) 
DF3.m[, c("level", "DF")] <- with(DF3.m, colsplit(variable, "\\.", c("level", "DF"))) 
out2 <- dcast(data = DF3.m, ID + level ~ DF, value.var="value") 
colnames(out)[3:4] <- c("DF1", "DF2") 
out2 <- ddply(out, "ID", summarize, count = sum(DF1 == DF2)) 

#Are they the same? 
all.equal(out1, out2) 
#[1] TRUE 

> head(out1) 
    ID count 
1 1  4 
2 2 NA 
3 3 NA 
4 5  3 
5 6  2 
6 9 NA 
+0

Vielen Dank @Chase. Elegant! Mágico! Qué Grande !!! – Nestorghh

+0

eine weitere Frage @Chase ... könntest du mir geben, wie sich dieser Ansatz ändert, wenn ich jetzt die counts von Nullen und Einsen getrennt benötige, dh ich brauche einen neuen Datenrahmen mit drei Spalten, der Benutzerkennung und der Zählung für Nullen und Einsen . Vielen Dank im Voraus. – Nestorghh

0

Sie können dafür die Funktion apply verwenden. Um die Summe jeder Zeile zu erhalten, können Sie verwenden:

sums <- apply(df1[2:ncol(df1)], 1, sum) 
cbind(df1[1], sums) 

, die die Summe aller, aber die erste Spalte zurück, dann binden, dass auf die erste Spalte die ID zurück zu bekommen.

Sie könnten das für beide Datenrahmen tun. Ich bin nicht wirklich klar, was das gewünschte Verhalten danach ist, aber vielleicht sehen Sie sich die merge Funktion an.

+0

Danke @Jeff Allen, aber das ist nicht was ich brauche. Ich denke du hast meine Frage falsch verstanden. – Nestorghh

+3

'rowSums (DF1 [, -1])' wird sich ebenfalls als schneller erweisen. – Chase

2
SELECT 
    COALESCE(DF1.ID, DF2.ID) AS ID, 
    CASE WHEN DF1.c1 = DF2.c1 THEN 1 ELSE 0 END + 
    CASE WHEN DF1.c2 = DF2.c2 THEN 1 ELSE 0 END + 
    CASE WHEN DF1.c3 = DF2.c3 THEN 1 ELSE 0 END + 
    CASE WHEN DF1.c4 = DF2.c4 THEN 1 ELSE 0 END + 
    CASE WHEN DF1.c5 = DF2.c5 THEN 1 ELSE 0 END AS count_of_matches 
FROM 
    DF1 
FULL OUTER JOIN 
    DF2 
    ON DF1.ID = DF2.ID 
2

Es gibt wahrscheinlich eine elegantere Art und Weise, aber das funktioniert:

x <- merge(DF1,DF2,by="ID",all=TRUE) 
pre <- paste("c",1:5,sep="") 
x$Count <- rowSums(x[,paste(pre,"x",sep=".")]==x[,paste(pre,"y",sep=".")]) 
DF_Return <- x[,c("ID","Count")] 
+0

Ganz ähnliche Ansätze haben wir hier ... lässt mich wissen, dass ich etwas auf dem richtigen Weg bin! +1 – Chase

+0

@Chase: vereinbart. Ich mag deine allgemeinere Lösung. –

Verwandte Themen