R How to use which() with floating point values?

后端 未结 5 847
走了就别回头了
走了就别回头了 2020-12-11 20:11

I have run into the same problem as described at R which () function returns integer(0)

price = seq(4,7, by=0.0025)
allPrices = as.data.frame(price)
lookupP         


        
相关标签:
5条回答
  • 2020-12-11 20:34

    You can sapply over all the prices and apply the all.equal function to each one, to find the one that is TRUE

    which(sapply(price, all.equal, lookupPrice) == TRUE)
    # [1] 425
    
    0 讨论(0)
  • 2020-12-11 20:35

    I just had the exact same problem.

    I initially fixed it by converting both sets of data from numeric to characters with as.character() before calling which().

    However, I wanted to figure out exactly why it wasn't working with the numeric data and did some further troubleshooting.

    It appears that the problem is with the way R generates decimal sequences with seq(). Using the round() function works - as suggested by Tim Biegeleisen - but I think you only need to apply it to the numbers generated by seq(). You can check out my work below - the error is very sporadic, I just tried numbers until I found one that failed: 19.2.

    > data <- 19.2
    > x.seq <- seq(5, 45, 0.2)
    > x.seq[72]
    [1] 19.2
    > 
    > data == 19.2
    [1] TRUE
    > x.seq[72] == 19.2
    [1] FALSE
    > data == x.seq[72]
    [1] FALSE
    > data == round(x.seq[72], digits = 1)
    [1] TRUE
    > round(data, digits = 1) == x.seq[72]
    [1] FALSE
    
    0 讨论(0)
  • 2020-12-11 20:40

    You could also try rounding the prices in your data frame to 4 decimal places:

    which(round(allPrices$price, digits=4) == lookupPrice)
    [1] 425
    

    After rounding to 4 places, the precision of the lookupPrice and your data frame of prices should match.

    Demo

    0 讨论(0)
  • 2020-12-11 20:50

    There is a function near in dplyr:

    near(x, y, tol = .Machine$double.eps^0.5)
    

    For this case, you can try:

    which(near(allPrices$price, lookupPrice))
    #[1] 425
    
    0 讨论(0)
  • 2020-12-11 20:53

    A manual approach to this involves specifying the tolerance for the comparison and doing:

    # tol = 1e-7: comparison will be TRUE if numbers are equal up to 
    #   7 decimal places
    tol = 1e-7
    which(abs(allPrices$price - lookupPrice) < tol)
    
    0 讨论(0)
提交回复
热议问题