R中的子集数据帧基于匹配多个变量的多个范围

时间:2014-10-21 00:54:34

标签: r filter subset

我遇到的问题似乎与之前提出的一些问题类似,但有些不同,以至于我无法找到优雅的解决方案。

我有一组需要与理论值数据库匹配的真实数据。我想基于多组多个条件进行过滤。例如,如果我有以下data.frame的理论值,

df <- data.frame(x=c(10,13,16,22,28,30), y=c(1:6))
> df
   x y
1 10 1
2 13 2
3 16 3
4 22 4
5 28 5
6 30 6

我有以下真实数据,

realdata <- data.frame(x=c(10.05, 13.06, 22.01),y=c(1.02, 1.99, 3.96))
> realdata
      x    y
1 10.05 1.02
2 13.06 1.99
3 22.01 3.96

我可以通过以下方式轻松搜索哪些理论行对应于我的实际数据中的行:

tolerance <- .10
subset(df, x>(realdata[1,1]-tolerance) & x<(realdata[1,1]+tolerance) & 
+ y>(realdata[1,2]-tolerance) & y<(realdata[1,2]+tolerance))
subset(df, x>(realdata[2,1]-tolerance) & x<(realdata[2,1]+tolerance) & 
+ y>(realdata[2,2]-tolerance) & y<(realdata[2,2]+tolerance))
#...etc for each row of real data

但是如果没有编写循环,有没有办法对我的实际数据中的所有行执行此操作?基本上,我想在给定的容差范围内找到与我的实际数据中任何一行对应的所有理论行。实际上,我的理论和实际表格都有成千上万的观察结果,这是我做的很多事情,所以速度很重要,我想。

此外,如果有人知道使用在subset()内部工作的单个表达式来确定值是否在一个范围内的方法,那将是锦上添花。也许子集是使用的错误功能,但在这种情况下没关系。

2 个答案:

答案 0 :(得分:0)

您可以使用outer来计算dfrealdata之间的所有成对差异,并检查xy是否小于容差

tolerance <- .10

# x
xx <- abs(outer(df$x, realdata$x, "-")) < tolerance
# y
yy <- abs(outer(df$y, realdata$y, "-")) < tolerance

# if both are within the tolerance the sum of xx and yy will be 2
(mat <- xx + yy > 1)
#      [,1]  [,2]  [,3]
#[1,]  TRUE FALSE FALSE
#[2,] FALSE  TRUE FALSE
#[3,] FALSE FALSE FALSE
#[4,] FALSE FALSE  TRUE
#[5,] FALSE FALSE FALSE
#[6,] FALSE FALSE FALSE

因此,mat的第一列显示df的哪些行在公差范围内(在本例中为第一列)。

非常优雅地按照realdata

行的顺序返回df中的匹配行
lapply(1:ncol(mat), function(i) df[mat[,i], ])

# return all matched data
df[row(mat)[mat], ]

答案 1 :(得分:0)

这是一个带矢量化测试的隐式循环:

 apply( realdata, 1, 
       function(x)  abs( x[1] - df[,1] ) < tolerance & 
                     abs( x[2] - df[,2]) <tolerance )
 #------------------------
      [,1]  [,2]  [,3]
[1,]  TRUE FALSE FALSE
[2,] FALSE  TRUE FALSE
[3,] FALSE FALSE FALSE
[4,] FALSE FALSE  TRUE
[5,] FALSE FALSE FALSE
[6,] FALSE FALSE FALSE

这样做没有应用功能:

> kronecker( as.matrix(df), as.matrix(realdata), function(x,y) { abs(x -y) <tolerance} )[,c(1,4)]
       [,1]  [,2]
 [1,]  TRUE  TRUE
 [2,] FALSE FALSE
 [3,] FALSE FALSE
 [4,] FALSE FALSE
 [5,]  TRUE  TRUE
 [6,] FALSE FALSE
 [7,] FALSE FALSE
 [8,] FALSE FALSE
 [9,] FALSE FALSE
[10,] FALSE FALSE
[11,] FALSE FALSE
[12,]  TRUE  TRUE
[13,] FALSE FALSE
[14,] FALSE FALSE
[15,] FALSE FALSE
[16,] FALSE FALSE
[17,] FALSE FALSE
[18,] FALSE FALSE

您可以使用rowSums(。)== 2

合并它