Проблема с плавающей точкой при использовании% в% - PullRequest
3 голосов
/ 10 апреля 2020

Мне трудно использовать% в% при работе с проблемой с плавающей запятой, например

> x = seq(0.05, 0.3, 0.01)
> x %in% seq(0.15, 0.3, 0.01)
 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[25] FALSE  TRUE

Я знаю, это потому, что компьютер хранит числа с плавающей запятой, но есть ли такая функция, как dplyr::near который может быть использован для замены %in%? dplyr::near(x, y) не будет работать, если длина x отличается от y.

Большое спасибо!

Ответы [ 3 ]

1 голос
/ 10 апреля 2020

Вы можете использовать dplyr::near здесь, но так как near выполняет попарное сравнение, и вам нужно сравнить с любым значением в векторе, используйте sapply.

check_values <- seq(0.15, 0.3, 0.01)
sapply(x, function(x) any(dplyr::near(x, check_values)))

#[1]  FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
#[13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
#[25]  TRUE  TRUE
1 голос
/ 10 апреля 2020

Преобразование as.character.

as.character(x) %in% as.character(seq(0.15, 0.3, 0.01))
# [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
# [10] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
# [19]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE

Похоже, это также работает для более сложных случаев. Обратите внимание:

x <- c(.2999, .3, .2499, .25)
y <- c(.299, .3, .249, .25)

as.character(x) %in% as.character(y)
# [1] FALSE  TRUE FALSE  TRUE

При округлении нам нужно правильно вычислить цифры для обобщения,

round(x, 3) %in% round(y, 3)
# [1] TRUE TRUE TRUE TRUE
round(x, 4) %in% round(y, 4)
# [1] FALSE  TRUE FALSE  TRUE

, которые можно автоматизировать:

d <- max(nchar(c(x, y))) - 2
round(x, d) %in% round(y, d)
# [1] FALSE  TRUE FALSE  TRUE

Мы можем обернуть оба решения в функцию:

`%in2%` <- function(x, y) {
  d <- max(nchar(c(x, y))) - 2
  round(x, d) %in% round(y, d)
}
`%in3%` <- function(x, y) {
  as.character(x) %in% as.character(y)
}
x %in2% y
# [1] FALSE  TRUE FALSE  TRUE
x %in3% y
# [1] FALSE  TRUE FALSE  TRUE
1 голос
/ 10 апреля 2020

Использование чисел с плавающей точкой, округленных до двух десятичных знаков:

x <- round(seq(0.05, 0.3, 0.01), 2)
x %in% round(seq(0.15, 0.3, 0.01), 2)

                                                                 ^^ 0.15
 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
[13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[25]  TRUE  TRUE   <-- 0.3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...