2016-04-14 60 views
3

我想根据一组间隔从矢量中排除值。子集数据按R中的间隔集合

实施例的数据:

mydata <- sort(runif(100,0,300)) 
mIntervals <- data.frame(start = c(2,50,97,159) , end = c(5,75, 120, 160)) 

解决方法1:使用简单的子集() - 不适合 - mIntervals的长度可以是相当大的

溶液2:使用嵌套for循环

valid <- vector(length(mydata)) 
valid <- TRUE 
for(i in 1:length(mydata){ 
for(j in 1:length(mIntervals){ 
    if(mydata[i] > mIntervals[j,]$start & mydata[i] < mIntervals[j,]$end){ 
    valid[i] <- FALSE 
    } 
} 
} 
mydata[valid] 

此解决方案在R中花费太长时间。

Solution3:功能findIntervals

require(FSA) 
    valid <- findInterval(mydata, sort(c(mIntervals$start, mIntervals$end))) 
    mydata[is.even(valid)] 

Solution4:使用某种方式打包 '间隔',但也没有合适的功能(或许interval_overlap())

相当类似(但不相同)的问题已被讨论here。但是有整数向量的解决方案,而不是连续变量。

我没有更多的想法。解决方案编号3似乎是最好的,但我不喜欢它 - 它不健壮 - 你将不得不检查重叠间隔等。

有没有更好的解决这个非常简单的问题? Thx

实际数据:我在某些时间测量了光强度(日期时间,强度)。测量设备正在进行维护(开始,结束)的日期时间也有间隔。 现在我想清除数据=排除在维护期间测量的值(高效!)。

+0

这是否对你有用?我不确定你期望的输出是什么,但是基于我所能看到的来写这个。 'MYDATA [MYDATA> mIntervals $开始与MYDATA Bas

+0

修改你的'findInterval',你可以使用'MYDATA [findInterval(MYDATA,mIntervals $开始)<= findInterval (mydata,mIntervals $ end)]' –

+1

@Bas:这不起作用--mydata和mIntervals的长度不同,结果不是我想要的。但thx –

回答

7

使用的development version (1.9.7)data.table,我们可以尝试%anywhere%

library(data.table) 
# %anywhere% returns TRUE if mydata is within any mIntervals, else FALSE 
ans <- mydata[!mydata %anywhere% mIntervals] 

这将包括终点但是作为incbounds = TRUE是默认设置。如果您需要排除端点可以使用下面的语法:

mydata[!anywhere(mydata, mIntervals[, 1], mIntervals[, 2], incbounds = FALSE)] 
+1

哦,不错的新功能:https://github.com/Rdatatable/data.table/issues/679 – lukeA

3

下面是一个RCPP实现:

library(Rcpp); 
set.seed(12L); 
mydata <- sort(runif(100L,0,300)); 
mIntervals <- data.frame(start=c(2,50,97,159),end=c(5,75,120,160)); 
cppFunction(' 
    LogicalVector inIntervals(DoubleVector v, DoubleVector starts, DoubleVector ends) { 
     if (starts.size()!=ends.size()) 
      throw new std::invalid_argument("starts and ends must be same length."); 
     LogicalVector res(v.size(),false); 
     for (int i = 0; i < v.size(); ++i) { 
      double val = v[i]; 
      for (int j = 0; j < starts.size(); ++j) 
       if (val>starts[j] && val<ends[j]) { 
        res(i) = true; 
        break; 
       } 
     } 
     return res; 
    } 
'); 
mydata[!inIntervals(mydata,mIntervals$start,mIntervals$end)]; 
## [1] 6.863323 10.168687 13.765236 16.585860 20.808275 28.508376 29.355912 
## [8] 30.534403 33.809681 37.152610 42.659676 45.787152 46.319152 47.274177 
## [15] 47.877135 49.281417 78.640425 79.475513 80.383078 80.814563 88.273175 
## [22] 93.344382 94.136411 94.736104 96.603457 126.327013 130.399146 131.800295 
## [29] 131.828798 137.282145 148.542361 151.430386 162.212264 162.541752 165.648249 
## [36] 166.758025 167.388096 172.243474 172.603380 176.544549 182.477693 189.979382 
## [43] 192.404449 192.499610 199.703949 200.945789 202.035664 208.173427 210.533571 
## [50] 212.949140 214.431451 215.524016 224.951507 225.608016 229.180120 230.324658 
## [57] 232.415456 236.278594 236.350904 244.164168 244.218976 244.669498 245.332560 
## [64] 247.184695 253.110672 253.267796 263.339092 263.352697 264.826916 267.979469 
## [71] 282.326263 282.786520 285.996158 291.379637 293.290767 294.260683 
2

我不知道如何有效的,这将是的,但是...

vbetween <- Vectorize(dplyr::between, vectorize.args = c("left", "right"), SIMPLIFY=F) 
mydata[!Reduce("|", vbetween(mydata, mIntervals$start, mIntervals$end))] 
+1

这只是隐藏循环..此外''dplyr :: between()'不允许开放边界IIRC(这是OP似乎正在寻找)。 – Arun

6

如果你重新排列你的时间间隔,您可以使用cut功能,然后仅取出奇数间隔:

NEWinterval <- c(2,5,50,75,97,120,159,160) 
mydata[cut(mydata, NEWinterval,labels = F) %% 2 != 0] 
+0

真的很高雅... +1 –

0

我想通过使用rolljoin使用data.table包显示另一种方法。

首先你融化并责令间隔的数据帧:

mIntervals.dt <- data.table(mIntervals) 
Intervals.melt <- melt(mIntervals.dt, measure.vars = c("start", "end")) 

订单数据和使用卷加盟:

mydata.dt <- data.table(mydata) 
setkey(Intervals.melt, value) 
setkey(mydata.dt) 

final.dt <- Intervals.melt[mydata.dt, roll = -Inf] 

仅取数据与“结束”值,因为你已经使用-Inf (与mIntervals中下一个最接近的值合并)。

final.dt[variable == "end"] 

非常快且灵活。