【问题标题】:How to identify overlaps in multiple columns如何识别多列中的重叠
【发布时间】:2015-02-16 11:30:50
【问题描述】:

我有一个数据集 (mydata),其中包含多个列,这些列可能适合存储在另一个数据集 (mycomparison) 中的范围内。

我想将mycomparison 加入mydata,其中mydata 的值在mycomparison 的范围内。

MWE

library(data.table)

mydata<-data.table(
  id=1:5,
  val1=seq(10000, 50000, by=10000),
  val2=floor(rnorm(5,mean=400,sd=100)),
  val3=rnorm(5,mean=.7,sd=.1)
)

mycomparison<-data.table(
  Name=LETTERS[1:3],
  minval1=c(0,30000,10000),
  maxval1=c(50000,80000,30000),
  minval2=c(300,400,300),
  maxval2=c(800,800,800),
  minval3=c(0,.5,.2),
  maxval3=c(1,.9,.8),
  correspondingval=c(.1,.2,.3)
)

期望的输出

> mydata.withmatches
   id  val1 val2      val3 Name minval1 maxval1 minval2 maxval2 minval3 maxval3 correspondingval
1:  1 10000  387 0.4844319    A       0   50000     300     800       0       1              0.1
2:  2 20000  425 0.7856313   NA      NA      NA      NA      NA      NA      NA               NA
3:  3 30000  324 0.8063969   NA      NA      NA      NA      NA      NA      NA               NA
4:  4 40000  263 0.5590113   NA      NA      NA      NA      NA      NA      NA               NA
5:  5 50000  187 0.8764396   NA      NA      NA      NA      NA      NA      NA               NA

当前解决方案

这感觉/非常笨拙,涉及交叉连接数据(使用optiRum::CJ.dt),进行大型逻辑检查,然后重新组装数据。

library(optiRum)

workingdt<-CJ.dt(mydata,mycomparison)

matched<-workingdt[val1>=minval1 &
                     val1<=maxval1 &
                     val2>=minval2 &
                     val2<=maxval2 &
                     val3>=minval3 &
                     val3<=maxval3][which.min(correspondingval)]
notmatched<-mydata[id!= matched[,id]]

all<-list(matched,notmatched)

mydata.withmatches<- rbindlist(all, fill=TRUE, use.names=TRUE)

寻找更好的解决方案 - 已更新

我知道foverlaps,但它只适用于单个间隔,而不是像这种情况下的许多范围。

我希望有一个不那么笨重、更优雅的解决方案。

【问题讨论】:

  • A previous foverlaps Q&A 似乎与您的情况相似:单个“点”(您:例如 val1,其他 Q:pos)应与范围连接(您:例如 minval1 /maxval1,其他问:start/end)。 @arun 写道:“你的问题是这种重叠连接的一个特例,开始和结束坐标是相同的”,(val1-val1pos-pos)。 @arun 的诀窍是创建第二个 pos 变量 (pos2 := pos)。这也可能是您向前迈出的第一步。
  • 干杯 @Henrik - 我不确定创建大量额外的列是否会特别优雅 - 我将尝试虚拟列解决方案
  • @Henrik 在探索中看起来 foverlaps 在尝试在多个范围内使用时可能不可行
  • 这是旧的,但匹配的不是比显示的多吗?即 id 2 也在名称 A 中。
  • 当我放入 rnorms 以允许重复测试以确保不返回重复行时,它会有所不同

标签: r data.table


【解决方案1】:

我不完全理解您的所需输出,因为多个 id 与 mycomparison data.table 匹配。使用您的数据(四舍五入到小数点后两位):

> mydata
   id  val1 val2 val3
1:  1 10000  387 0.48
2:  2 20000  425 0.79
3:  3 30000  324 0.81
4:  4 40000  263 0.56
5:  5 50000  187 0.88

> mycomparison
   Name minval1 maxval1 minval2 maxval2 minval3 maxval3 correspondingval
1:    A       0   50000     300     800     0.0     1.0              0.1
2:    B   30000   80000     400     800     0.5     0.9              0.2
3:    C   10000   30000     300     800     0.2     0.8              0.3

这给出了:

> workingdt
    id  val1 val2 val3 Name minval1 maxval1 minval2 maxval2 minval3 maxval3 correspondingval
 1:  1 10000  387 0.48    A       0   50000     300     800     0.0     1.0              0.1
 2:  2 20000  425 0.79    A       0   50000     300     800     0.0     1.0              0.1
 3:  3 30000  324 0.81    A       0   50000     300     800     0.0     1.0              0.1
 4:  4 40000  263 0.56    A       0   50000     300     800     0.0     1.0              0.1
 5:  5 50000  187 0.88    A       0   50000     300     800     0.0     1.0              0.1
 6:  1 10000  387 0.48    B   30000   80000     400     800     0.5     0.9              0.2
 7:  2 20000  425 0.79    B   30000   80000     400     800     0.5     0.9              0.2
 8:  3 30000  324 0.81    B   30000   80000     400     800     0.5     0.9              0.2
 9:  4 40000  263 0.56    B   30000   80000     400     800     0.5     0.9              0.2
10:  5 50000  187 0.88    B   30000   80000     400     800     0.5     0.9              0.2
11:  1 10000  387 0.48    C   10000   30000     300     800     0.2     0.8              0.3
12:  2 20000  425 0.79    C   10000   30000     300     800     0.2     0.8              0.3
13:  3 30000  324 0.81    C   10000   30000     300     800     0.2     0.8              0.3
14:  4 40000  263 0.56    C   10000   30000     300     800     0.2     0.8              0.3
15:  5 50000  187 0.88    C   10000   30000     300     800     0.2     0.8              0.3

然后离开你的which.min()

> workingdt[val1>=minval1 & val1<= maxval1 & val2>=minval2 &
            val2<=maxval2 & val3>=minval3 & val3<=maxval3]
   id  val1 val2 val3 Name minval1 maxval1 minval2 maxval2 minval3 maxval3 correspondingval
1:  1 10000  387 0.48    A       0   50000     300     800     0.0     1.0              0.1
2:  2 20000  425 0.79    A       0   50000     300     800     0.0     1.0              0.1
3:  3 30000  324 0.81    A       0   50000     300     800     0.0     1.0              0.1
4:  1 10000  387 0.48    C   10000   30000     300     800     0.2     0.8              0.3
5:  2 20000  425 0.79    C   10000   30000     300     800     0.2     0.8              0.3

如果您使用 data.table 分组功能,您可以为每个 id 选择 min(correspondingval)(我暂时不考虑不匹配的数据):

> workingdt[val1>=minval1 & val1<= maxval1 & val2>=minval2 & 
            val2<=maxval2 & val3>=minval3 & val3<=maxval3]
                   [,.SD[which.min(correspondingval)], by=id]
   id  val1 val2 val3 Name minval1 maxval1 minval2 maxval2 minval3 maxval3 correspondingval
1:  1 10000  387 0.48    A       0   50000     300     800       0       1              0.1
2:  2 20000  425 0.79    A       0   50000     300     800       0       1              0.1
3:  3 30000  324 0.81    A       0   50000     300     800       0       1              0.1

或者,如果您愿意,也可以使用 max(correspondingval)

> workingdt[val1>=minval1 & val1<= maxval1 & val2>=minval2 &
            val2<=maxval2 & val3>=minval3 & val3<=maxval3]
                   [,.SD[which.max(correspondingval)], by=id]
   id  val1 val2 val3 Name minval1 maxval1 minval2 maxval2 minval3 maxval3 correspondingval
1:  1 10000  387 0.48    C   10000   30000     300     800     0.2     0.8              0.3
2:  2 20000  425 0.79    C   10000   30000     300     800     0.2     0.8              0.3
3:  3 30000  324 0.81    A       0   50000     300     800     0.0     1.0              0.1

如果你想要的——如 Desired Output 中所示——是具有最小 correspondingval 的第一行以及具有 NA 的所有其他内容,那么有更简单的方法可以做到这一点。如果您想知道每个 id 与某个范围匹配的位置——正如我在输出中显示的那样——那么更简洁、更优雅的解决方案是不同的。

告诉我。

【讨论】:

    【解决方案2】:

    好问题!您可以在下面找到我的快速修复,但对于我的口味来说,它仍然有点笨拙

    生成的mydata集合:

       id  val1 val2      val3
    1:  1 10000  377 0.7912443
    2:  2 20000  378 0.7709792
    3:  3 30000  484 0.7049517
    4:  4 40000  513 0.5169590
    5:  5 50000  474 0.7987448
    

    一个简单的函数来过滤掉比较数据集中不匹配的行(多行可以匹配)。

    library(dplyr)
    
    find_interval_func<-function(var.min.name, var.max.name, value, val.to.return){
      compset<-data.frame(mycomparison)
    
      for(i in 1:length(var.min.name)){
    
        compset<-
          compset %>%
          filter_(paste0(var.min.name[[i]], "<=", value[[i]]),
                  paste0(var.max.name[[i]], ">", value[[i]]))    
      }
    
      paste(compset[,val.to.return], collapse="|")
    
    }
    

    结果:

    > mydata %>%
    +   group_by(1:n()) %>%
    +   mutate(matchedValue = find_interval_func(c("minval1", "minval2", "minval3"),
    +                                        c("maxval1", "maxval2", "maxval3"),
    +                                        c(val1, val2, val3), 
    +                                        "Name"))
    Source: local data table [5 x 6]
    
      id  val1 val2      val3 1:n() matchedValue
    1  1 10000  377 0.7912443     1          A|C
    2  2 20000  378 0.7709792     2          A|C
    3  3 30000  484 0.7049517     3          A|B
    4  4 40000  513 0.5169590     4          A|B
    5  5 50000  474 0.7987448     5            B
    

    【讨论】:

      猜你喜欢
      • 2020-12-27
      • 1970-01-01
      • 1970-01-01
      • 2013-05-02
      • 2017-01-31
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      • 2016-04-22
      相关资源
      最近更新 更多