【问题标题】:How to include a level of error in matching/comparing data frames in R如何在 R 中匹配/比较数据帧时包含一定程度的错误
【发布时间】:2016-12-06 08:22:19
【问题描述】:

我是 R 新手,我正在尽我最大的努力(到目前为止;非常好),但我遇到了问题。我有两个数据框,一个是理论值,另一个是实验值,并且数据框的长度不一样。我想比较两个数据框以找到它们之间的匹配值。由于它是理论值与实验值,我需要在匹配值时包含一定程度的误差,例如理论值的±0.5。这就是我遇到问题的地方 - 我不知道如何包含此错误。

数据框很大,但下面是我尝试过的示例。

Theory <- c("195.0882",
            "196.0852",
            "196.0916",
            "300.1600",
            "288.1752",
            "289.1786",
            "290.1819",
            "393.2077",
            "394.2111")

Experi <- c("195.0312",
            "196.0340",
            "196.1251",
            "288.1856",
            "289.1786",
            "290.1819")


T <- data.frame(Theory)
E <- data.frame(Experi)
M1 <- merge.default(T, E)
M2 <- match(Theory, Experi)
M2
# [1] NA NA NA NA NA  5  6 NA NA

merge 和 match 都没有出错的余地,而 compare 包似乎也无济于事。

【问题讨论】:

  • github上有一个包叫fuzzyjoin——你可以在那里找到它——github.com/dgrtwo/fuzzyjoin
  • 您想尝试将Theory 中的每个值Experi 中的每个值 进行匹配吗?或者这些值是否按顺序排列,因此只需要比较平行的值对?或者您是否希望为Theory 中的每个值最多找到一个匹配项?如果有两个候选人参加比赛,但一个比另一个更接近怎么办?
  • 我希望从“理论”中的“经验”中找到一个值,但存在一定程度的错误。所以没有必要匹配每个值。而且这些值不是按顺序排列的,所以没有平行对比较。如果有两个候选匹配,我希望 a 可以降低错误级别以仅获得一个匹配。

标签: r dataframe merge compare match


【解决方案1】:

我们可以使用data.table::foverlaps 函数进行重叠合并。首先我们需要准备数据,为理论值创建范围。

library(data.table)

# set tolerance for merge
tolerance <- 0.5

# Theory data, prepare data with tolerance for Start/End
dt_T <- data.table(
  Theory = as.numeric(Theory),
  Start = as.numeric(Theory) - tolerance,
  End = as.numeric(Theory) + tolerance, 
  key= c("Start", "End"))

# Experi data, Start/End are the same
dt_E <- data.table(
  Experi = as.numeric(Experi),
  Start = as.numeric(Experi),
  End = as.numeric(Experi), 
  key= c("Start", "End"))

# merge with overlap
foverlaps(dt_E, dt_T)
#      Theory    Start      End   Experi  i.Start    i.End
# 1: 195.0882 194.5882 195.5882 195.0312 195.0312 195.0312
# 2: 196.0852 195.5852 196.5852 196.0340 196.0340 196.0340
# 3: 196.0916 195.5916 196.5916 196.0340 196.0340 196.0340
# 4: 196.0852 195.5852 196.5852 196.1251 196.1251 196.1251
# 5: 196.0916 195.5916 196.5916 196.1251 196.1251 196.1251
# 6: 288.1752 287.6752 288.6752 288.1856 288.1856 288.1856
# 7: 289.1786 288.6786 289.6786 289.1786 289.1786 289.1786
# 8: 290.1819 289.6819 290.6819 290.1819 290.1819 290.1819

【讨论】:

    【解决方案2】:

    根据您的评论,您说您只想为每个实验值获得一个理论值,即使多个理论值满足公差。您暗示,如果有多个候选人满足容差,您希望选择所有候选人中最接近的匹配。但是你也说没有必要匹配每个值。我认为这是一个矛盾。如果您需要在所有理论值中选择最接近匹配的理论值,那么这意味着您需要将每个实验值与所有个理论值进行比较,以确保您选择所有理论值中最接近的匹配。

    findInterval() 函数适合此目的。通过首先对理论向量进行排序,我们可以将其用作findInterval()vec 参数,这将允许使用二进制搜索来找到每个实验值的下限。我们可以指定all.inside=T来保证返回的索引都在排序后的理论向量内(并且不指向最后一个元素),然后对相邻元素执行额外的tiebreaker,当上元素实际上更接近于实验值低于元素。

    最后,我们可以应用公差。从您的问题看来,您可能希望为没有匹配理论值的实验值返回 NA,IOW 没有满足公差的理论值。如果不满足相应实验值的容差,我们可以通过用 NA 覆盖上一步中发现的理论值来轻松实现这一要求。

    另外,小问题:我不确定您为什么将向量定义为字符。我们需要数值来执行这些操作。

    因此:

    theory <- c(195.0882,196.0852,196.0916,300.16,288.1752,289.1786,290.1819,393.2077,394.2111);
    experi <- c(195.0312,196.034,196.1251,288.1856,289.1786,290.1819);
    
    ## sort theory for findInterval() binary search
    theory <- sort(theory);
    
    ## get closest match for each experi element
    i <- findInterval(experi,theory,all.inside=T);
    inc <- which(abs(theory[i+1L]-experi)<abs(theory[i]-experi));
    i[inc] <- i[inc]+1L;
    
    ## init result vector
    res <- theory[i];
    
    ## replace with NA any result elements whose deviations exceed the tolerance
    res[abs(res-experi)>0.5] <- NA_real_;
    
    ## show result in a nice format
    data.frame(experi,res,error=experi-res);
    ##     experi      res   error
    ## 1 195.0312 195.0882 -0.0570
    ## 2 196.0340 196.0852 -0.0512
    ## 3 196.1251 196.0916  0.0335
    ## 4 288.1856 288.1752  0.0104
    ## 5 289.1786 289.1786  0.0000
    ## 6 290.1819 290.1819  0.0000
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-13
      • 1970-01-01
      • 1970-01-01
      • 2017-06-12
      • 2016-08-12
      • 1970-01-01
      • 2019-07-26
      • 1970-01-01
      相关资源
      最近更新 更多