我已经挣扎了一段时间,我找不到出路。这是我的问题。
我有2个数据帧:
df1 <- data.frame(replicate(3,sample(1:10,20,rep=TRUE)))
df1
X1 X2 X3
1 10 1 9
2 3 4 2
3 7 6 8
4 8 10 7
5 5 7 5
6 8 5 9
7 9 8 4
8 6 2 7
9 2 9 6
10 5 2 9
df2 <- data.frame(df1[sample(nrow(df1),4), ])
df2
X1 X2 X3
8 6 2 7
3 7 6 8
10 5 2 9
7 9 8 4
我想创建长度(x)=长度(df1)的向量 x ,每行包含 df1 , df2 中相应行的行索引(即 df1 和 df2 之间每列的相同精确值)。
考虑一下:
dim(df1)
[1] 1096188 3
dim(df2)
[1] 256 3
并且 df1 有几行具有相同的值(即相应的行索引将是相同的),原则上 df1 中的所有行都应该找到与 df2 中的行匹配。
预期输出为:
x
[1] 0 0 2 0 0 0 4 1 0 3
希望这很清楚......
你能帮忙吗?谢谢,
PIERA
答案 0 :(得分:6)
以下是data.table
的选项:
require(data.table)
# first set the original orders (data.frame will be sorted when doing setkey)
setDT(df1)[, ori := .I]
setDT(df2)[, ind_df2 := .I]
# define keys
setkey(df1, X1, X2, X3)
setkey(df2, X1, X2, X3)
# compute the indices of the df1 line in df2
x <- df2[df1, ind_df2]
# put the nomatch to 0
x[is.na(x)] <- 0
# Finally, put the original orders back and delete the variable ori
x <- x[order(df1$ori)]
df2 <- df2[order(df2$ind_df2)]
df1[, ori:=NULL]
df2[, ind_df2:=NULL]
结果x(包含您的数据):
x
#[1] 0 0 2 0 0 0 4 1 0 3
@Frank建议的另一个更简单有效的选项:
setkeyv(setDT(df2)[,ii:=.I],setdiff(names(df2),"ii"))
x <- df2[df1]$ii
x[is.na(x)] <- 0
@nicola回答,@ Frank建议和我的答案之间的一些基准,在100000行df1和200行df2 ,上稍微修改了nicola的得到所需的输出答案(两个函数给出相同的结果,除了需要as.numeric
尼可拉的):
这样:
set.seed(17)
df1 <- data.frame(replicate(3,sample(1:100,100000,rep=TRUE)))
df2 <- data.frame(df1[sample(nrow(df1),200), ])
nicola <- function(){x<-match(do.call(paste,df1),do.call(paste,df2), nomatch=0)}
cath <- function(){
dt1 <-data.table(df1); dt1[, ori:=.I]
dt2 <- data.table(df2); dt2[, ind_df2:=.I]
setkey(dt1, X1, X2, X3)
setkey(dt2, X1, X2, X3)
x <- dt2[dt1, ind_df2]
x[is.na(x)] <- 0
x <- x[order(dt1$ori)]
x
}
Frank <- function(){dt1 <-data.table(df1);dt2 <- data.table(df2); setkey(setDT(dt2)[,ii:=.I],X1,X2,X3); x <- dt2[dt1]$ii;x[is.na(x)] <- 0}
require(microbenchmark)
microbenchmark(cath(), Frank(), nicola(), unit="relative", times=100)
#Unit: relative
# expr min lq mean median uq max neval cld
#Frank() 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 100 a
# cath() 3.238195 3.099896 2.438342 2.767165 2.177365 1.447397 100 b
#nicola() 13.127820 12.476996 8.761549 10.899191 7.292086 2.783436 100 c
答案 1 :(得分:3)
我只是尝试:
x <- rownames(df2)[match(do.call(paste, df1), do.call(paste, df2))]
x[is.na(x)] <- 0
关于它的期望输出有很多讨论;在@CathG解释中,这一行产生它:
match(do.call(paste, df1), do.call(paste, df2),nomatch=0)
答案 2 :(得分:0)
在您的示例中,df1中的行在df2中都不匹配(例如,第1行)。但是,如果他们这样做(也许df1中有多次出现多次行),你可以:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AddFriendsCell *cell = (AddFriendsCell *)[tableView cellForRowAtIndexPath:indexPath];
if(cell.chkAddFrdsYes.hidden==YES)
{
cell.chkAddFrdsNo.hidden=YES;
cell.chkAddFrdsYes.hidden=NO;
}
else
{
cell.chkAddFrdsNo.hidden=YES;
cell.chkAddFrdsYes.hidden=NO;
}
}
df1中实际上不在df2中的任何行都将保留为值0.也许不是最快的解决方案 - 您需要重复该过程多少次?
答案 3 :(得分:0)
我意识到这是一个非常古老的问题的新答案,但
出了什么问题match(data.frame(t(df1)), data.frame(t(df2)))
...
输出
[1] NA NA 2 NA NA NA 4 1 NA 3
所以有NA
而不是0
s,但我认为它只是一行,不需要do.call()
或其他任何内容。