Просто чтобы добавить к @Tens отличный ответ.
Что, кажется, происходит три вещи
- У вас есть вопрос с плавающей точкой (как уже упоминалось)
- Вы используете и старый data.table версия
- Вторичные индексы пиная в то время вы не знаете об этом
Использование установки
library(data.table)
options(digits = 20) # to see number representation
mround <- function (number, multiple) {
return(multiple * round(number/multiple))
}
DT = data.table(a = mround(112.3, 0.1), b = "B")
Так что давайте рассмотрим указанные выше пункты. Поскольку у вас есть с плавающей точкой и со ссылкой на ?setNumericRounding
Компьютеры не может представлять некоторые числа с плавающей точкой (например, 0.6) точно, используя основание 2. Это приводит к неожиданному поведению при соединении или группирования столбцов типа «числовой»; то есть«Двойной
Это привело data.table
УБС реализовать setNumericRounding
, которая автоматически округляется поплавки поэтому алгоритм радикс будет вести себя, как ожидалось.
До v1.9.8, setNumericRounding(2)
был по умолчанию (следовательно, ваш первый пример работает), но после нескольких жалоб от пользователей на непоследовательность GH (IIRC), так как v1.9.8 по умолчанию было установлено обратно setNumericRounding(0)
для того, чтобы должны соответствовать поведению data.frame
(см. here). Поэтому, если вы обновите свою таблицу data.table до последней версии, вы увидите, что оба data.table
и data.frame
будут вести себя одинаково для обоих ваших примеров (и оба ваших примера не удастся).
Сравнить
setNumericRounding(0)
DT[a == 112.3]
## Empty data.table (0 rows) of 2 cols: a,b
Для
setNumericRounding(1)
DT[a == 112.3]
# a b
# 1: 112.30000000000001 B
Так вы спросите, ", что на земле алгоритм Radix имеет отношение к чему здесь". Итак, мы достигли третьего пункта выше вторичные индексы (пожалуйста, прочтите this). Давайте посмотрим, что на самом деле происходит, когда вы работаете вам код, указанный выше
options(datatable.verbose = TRUE)
DT[a == 112.3] # works as expected, i.e returns one row
# Creating new index 'a' <~~~~
# forder took 0 sec
# Starting bmerge ...done in 0 secs
# a b
# 1: 112.30000000000001 B
Позволяет проверяет новые вторичные индексов
indices(DT)
#[1] "a"
, когда вы бежали ==
, data.table набор a
в качестве вторичного индекса в порядке для выполнения будущих операций намного эффективнее (это было введено в версии 1.9.4, см. here). Другими словами, вы выполнили двоичное соединение на a
вместо обычного векторного сканирования, как это было раньше v1.9.4. (В качестве побочной заметки это можно отключить, выполнив options(datatable.auto.index = FALSE)
, в этом случае ни один из ваших примеров не будет работать даже с setNumericRounding(1)
если не будет явно указать ключ, используя setkey
или on
аргумент)
Это, вероятно, будет также объяснить, почему
DT[a == 112.30000 & b == 'B']
не работает. Вы устанавливаете здесь два столбца, и ни вторичные индексы, ни двоичные соединения не выполняются (автоматически) для таких выражений, как == & ==
(пока), поэтому вы выполнили обычное векторное сканирование, а setNumericRounding(1)
не ударили в
Хотя, вы можете установить ключи вручную и заставить его работать, например (как я заметил под @Tens ответ), вы можете сделать
setNumericRounding(1) # make sure autoroundings turned on
DT[.(112.3, 'B'), nomatch = 0L, on = .(a, b)]
# Calculated ad hoc index in 0 secs
# Starting bmerge ...done in 0 secs
# a b
# 1: 112.3 B
Или используя старый способ
setkey(DT, a, b)
DT[.(112.3, 'B'), nomatch = 0L]
# Starting bmerge ...done in 0 secs
# a b
# 1: 112.3 B
You проблема четко не определена. Вы должны добавить то, что ожидаете от вывода. Обе строки возвращают мне пустые data.tables. – lmo
Первый оператор не работает для меня в 'data.table', и он не связан с' data.table' или 'data.frame', но это проблема [точности с плавающей точкой] (https: // cran. r-project.org/doc/FAQ/R-FAQ.html#Why-doesn_0027t-R-think-these-numbers-are-equal_003f). См. «DT [(a - 112.3) <1.e-6 & b == 'B',] '(с использованием поля ошибки 0,000001, если вам нужна более высокая точность, см. ссылку выше или используйте' .Machine $ double.eps^0.5', как и 'all.equal') – Tensibai
FWIW, round принимает параметр 'digits',' round (112.3,1) 'должно быть достаточно и должно избегать вашей реальной проблемы) – Tensibai