4

我需要实现以下函数(理想情况下在 R 或 SQL 中):给定两个数据框(有一个用户 ID 列,其余列是布尔属性(它们只允许为 0 或 1))我需要返回具有两列(用户 ID 和计数)的新数据框,其中 count 是两个表中每个用户的 0 和 1 匹配数。用户 F 可能出现在两个数据帧中,也可能只出现在一个数据帧中。在最后一种情况下,我需要为该用户数返回 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

我的函数必须返回如下内容:(以下是子集)

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

您能给我一些建议来执行此操作吗?我不是 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)

提前谢谢了。此致!

4

5 回答 5

3

这是适合您的方法。第一个硬编码要比较的列,而另一个更通用且不知道 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
于 2012-04-13T17:19:10.700 回答
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
于 2012-04-13T16:22:03.477 回答
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")]
于 2012-04-13T17:18:28.347 回答
1

我们可以safe_full_join从我的包safejoin中使用,并== 在冲突的列之间应用。这将产生一个新的数据框,其中包含我们可以使用的逻辑 c*rowSums

# devtools::install_github("moodymudskipper/safejoin")
library(safejoin)
library(dplyr)

safe_full_join(DF1, DF2, by = "ID", conflict = `==`) %>%
  transmute(ID, count = rowSums(.[-1]))
#    ID count
# 1   1     4
# 2  10    NA
# 3   5     3
# 4  20    NA
# 5   3    NA
# 6   6     2
# 7  71    NA
# 8  15     1
# 9  80     1
# 10 78    NA
# 11 98    NA
# 12  2    NA
# 13  9    NA
于 2019-02-26T00:29:00.610 回答
0

您可以使用该apply函数来处理此问题。要获得每一行的总和,您可以使用:

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

这将返回除第一列之外的所有列的总和,然后将其绑定到第一列以取回 ID。

您可以在两个数据帧上执行此操作。我不太清楚在那之后想要的行为是什么,但也许看看这个merge功能。

于 2012-04-13T16:12:11.823 回答