2012-04-13 9 views
4

私は以下の関数を実装する必要があります(理想的にはRまたはSQL):与えられた2つのデータフレーム(useridの列と残りの列はブール値の属性です(0または1にすることができます)) 2つの列(useridとcount)を持つ新しいデータフレームを返します。countは、両方のテーブルの各ユーザーの0と1の一致数です。ユーザFは、両方のデータフレームで発生する可能性があります。この最後のケースでは、そのユーザー数に対してNAを返す必要があります。私は例を記述します(以下のサブセットです)SQLまたはRライブラリsqldfを使用してこのタスクをどのように行いますか?

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

あなたは私にこれを実行するための任意の提案を与えることができる:

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 

My機能は、このような何かを返す必要がありますか?私はSQLの専門家ではない。

私は上記で使用した実験を生成するためにコードをRに入れました。

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) 

事前に感謝します。 よろしく!

+0

どのDBMSを使用していますか? PostgreSQL?オラクル? DB2? .. –

+0

こんにちは、私はMicrosoft SQL Server 2005を使用しています!ありがとう – Nestorghh

答えて

3

は、ここにあなたのためのアプローチです。最初の列は比較する列をハードコードしますが、もう1つはDF1と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

ありがとうございます@チェイス。エレガント!マジコ!クーグランデ!!! – Nestorghh

+0

もう1つの質問@Chase ...私は0と1のカウントが別々に必要な場合、このアプローチがどう変わるか教えてください。つまり、3つの列を持つ新しいデータフレームが必要です。ユーザーIDと0と1のカウント。事前にどうもありがとうございました。 – Nestorghh

0

apply関数を使用してこれを処理できます。各行の合計を取得するには、使用することができます。最初の列以外のすべての合計を返します

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

は、その後、戻ってIDを取得するために、最初の列にそれをバインドします。

両方のデータフレームでこれを行うことができます。私は実際にそれが何であるかはっきりしていませんが、mergeの機能を見てください。

+0

ありがとう@ジェフアレン、それは私が必要なものではありません。私はあなたが私の質問を誤解したと思います。 – Nestorghh

+3

'rowSums(DF1 [、-1])'も高速になります。 – 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

は、おそらくよりエレガントな方法はありますが、これは動作します:

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

私たちがここにあるのと非常に似たアプローチ...私はちょっと正しい道にいると知っています! +1 – Chase

+0

@チェイス:合意。私はあなたのより一般的な解決策が好きです。 –

関連する問題