R в data.table усекающие биты?

Так что я огромныйdata.table фанат в R. Я использую его почти все время, но столкнулся с ситуацией, в которой он не будет работать для меня вообще. У меня есть пакет (внутренний для моей компании), который использует Rdouble хранить значение беззнакового 64-битного целого числа, чья битовая последовательность соответствует некоторому причудливому кодированию. Этот пакет работает очень хорошо везде, кроме data.table. Я обнаружил, что если я агрегирую по столбцу этих данных, я теряю большое количество своих уникальных значений. Мое единственное предположение здесь, чтоdata.table усекать биты в какой-то странныйdouble оптимизация.

Кто-нибудь может подтвердить, что это так? Это просто ошибка?

Ниже приведена репродукция проблемы и сравнение с пакетом, который я в настоящее время должен использовать, но хочу избежать со страстью (dplyr).

temp <- structure(list(obscure_math = c(6.95476896592629e-309, 6.95476863436446e-309, 
6.95476743245288e-309, 6.95476942182375e-309, 6.95477149408563e-309, 
6.95477132830476e-309, 6.95477132830476e-309, 6.95477149408562e-309, 
6.95477174275702e-309, 6.95476880014538e-309, 6.95476896592647e-309, 
6.95476896592647e-309, 6.95476900737172e-309, 6.95476900737172e-309, 
6.95476946326899e-309, 6.95476958760468e-309, 6.95476958760468e-309, 
6.95477020928318e-309, 6.95477124541406e-309, 6.95476859291965e-309, 
6.95476875870014e-309, 6.95476904881676e-309, 6.95476904881676e-309, 
6.95476904881676e-309, 6.95476909026199e-309, 6.95476909026199e-309, 
6.95476909026199e-309, 6.95476909026199e-309, 6.9547691317072e-309, 
6.9547691317072e-309, 6.9547691317072e-309, 6.9547691317072e-309, 
6.9547691317072e-309, 6.9547691317072e-309, 6.9547691317072e-309, 
6.9547691317072e-309, 6.9547691317072e-309, 6.9547691317072e-309, 
6.9547691317072e-309, 6.9547691317072e-309, 6.95477211576406e-309, 
6.95476880014538e-309, 6.95476880014538e-309, 6.95476880014538e-309, 
6.95476892448104e-309, 6.95476880014538e-309, 6.95476892448105e-309, 
6.9547689659263e-309, 6.95476913170719e-309, 6.95476933893334e-309
)), .Names = "obscure_math", class = c("data.table", "data.frame"), row.names = c(NA, 
-50L))

dt_collapsed <- temp[, .(count=.N), by=obscure_math]
nrow(dt_collapsed) == length(unique(temp$obscure_math))

setDF(temp)
dplyr_collapsed <- temp %>% group_by(obscure_math) %>% summarise(count=n())
nrow(dplyr_collapsed) == length(unique(temp$obscure_math))
 Steven Beaupré04 июн. 2016 г., 02:36
Я могу копировать тоже с помощью v1.9.7
 Arun04 июн. 2016 г., 03:01
Мы рекомендуем использоватьbit64::integer64 для 64-битных целых чисел (вместо двойных). Увидеть?setNumericRounding (и пример), почему мы округляем последние 2 байта. В связи с этим возникла проблема (но с упорядочением data.table, а не с группировкой), но у нас еще не было времени, чтобы решить, как лучше с ней справиться,# 1642.
 stanekam04 июн. 2016 г., 04:14
@ Арун Вау. Это поразило меня тем, что вы округлили последние 16 битов всех двойных по умолчанию для этих операций. Насколько я могу судить, это ужасное дизайнерское решение. Вы делаете ужасно большие предположения о том, что составляет «много цифр». Неудовлетворительно. Пожалуйста, добавьте в качестве ответа, чтобы я мог принять и закрыть этот вопрос.
 thelatemail04 июн. 2016 г., 02:34
Я могу повторить это на data.table 1.9.6.aggregate дает также 26 строк, ноdata.table т 21. Используяby=as.character(obscure_math) также дает правильные 26 строк
 stanekam04 июн. 2016 г., 02:41
@thelatemail Я не уверен, что это должно иметь значение. Пакет не должен изменять значение данных пользователя в такой операции. Это очень непрозрачно, что значениеby переменная должна быть изменена вообще. Я предполагаю, что это как-то связано с оптимизацией радикальной сортировки, но никто не должен ожидать потери точности (и в этом случае полной непригодности) от такой операции.
 thelatemail04 июн. 2016 г., 02:37
Правда, это очень маленькие числа, вероятно, ниже типичной ошибки округления.

Ответы на вопрос(1)

Решение Вопроса

Обновить: функция округления по умолчанию была удалена втекущая версия разработки data.table (v1.9.7), Смотрите инструкции по установке для версии devel.Вот.

Это также означает, что вы несете ответственность за понимание ограничений в представлении чисел с плавающей запятой и работе с ними.

data.table существует уже давно. Мы привыкли иметь дело с ограничениями в представлениях с плавающей запятой, используяпорог (как это делает основание R, например,all.equal). Однако он просто не работает, так как он должен быть адаптивным в зависимости от того, насколько велики сравниваемые цифры.Эта серия статей это отличное чтение по этой теме и другим потенциальным вопросам.

Это повторяющаяся проблема, потому что а) люди не осознают ограничений, или б)порогИнг не действительно помогли их проблеме, означало, что люди продолжали спрашивать здесь или публиковать на странице проекта.

Хотя мы переопределили порядок в data.table для быстрого радикального упорядочения, мы воспользовались возможностью, чтобы предоставить альтернативный способ решения проблемы и предоставить выход, если он окажется нежелательным (экспортsetNumericRounding). С № 1642,заказ вероятно, не требуется округлять двойные значения (но это не так просто, поскольку порядок напрямую влияет на подмножества на основе бинарного поиска).

Актуальная проблема здесьгруппировка по числам с плавающей запятойЕще хуже такие цифры, как в вашем случае. Это просто плохой выбор, ИМХО.

Я могу придумать два пути вперед:

При группировании по столбцам, которые на самом деле удваиваются (в R, 1 является двойным по сравнению с 1L, и в этих случаях нет проблем), мы предупреждаем, что последние 2 байта округлены, и что люди должны прочитать?setNumericRounding, А также предложить использоватьbit64::integer64.

Удалить функциональность разрешениягруппировка операции с действительно двойными значениями или заставить их фиксировать точность до определенных цифр, прежде чем продолжить. Я не могу придумать вескую причину, почему кто-то действительно хотел бы группировать по числам с плавающей запятой (хотел бы услышать от людей, которые делают).

То, что очень маловероятно, будет возвращаться кпорогНа основе проверок для определения, какие двойники должны принадлежать к той же группе.

Просто чтобы вопрос оставался в ответе, используйтеsetNumericRounding(0L).

 stanekam05 июн. 2016 г., 17:47
Ура, спасибо! Я бы предложил предупреждения с предложениями для группировки по двойникам. Я могу придумать причину, по которой пользователь сгруппировался бы по двойному. Это в моем вопросе :)
 Dirk Eddelbuettel04 июн. 2016 г., 12:39
Пальцы на явные ошибки, когда группировка делается на удваивается.
 Arun06 июн. 2016 г., 21:09
Причина, по которой вы указываете, что вы не используете свой пакет, не имеет для меня особого смысла, но все в порядке. Но, может быть, вы заинтересованы в том, чтобы снова оживить int64? Чтобы продолжать делать то, что вы делаете сейчас, будет / должен быть последний вариант ИМО. Конечно, не стесняйтесь использовать любой пакет, который вам нужен. Лучший.
 Arun06 июн. 2016 г., 13:02
@iShouldUseAName, извините, этоне уважительная причина. Для этого пакет вашей компании должен начать использовать 64-битные целые числа (используя bit64 или вашу собственную внутреннюю реализацию). Не злоупотреблять / тренироваться с двойниками.
 Arun04 июн. 2016 г., 12:57
@DirkEddelbuettel, спасибо. Я подал# 1728, Я согласен, что это лучший путь вперед.
 Arun06 июн. 2016 г., 21:06
Я ничего не знаю о вашем представлении о том, что это кодировка, которую использует ваша компания. Что касается bit64, я знаю, что нет никакой двусмысленности в представлении чисел как целых чисел64 (хотя они внутренне удваиваются). Например.,identical(3e8, 3e8*(1+.Machine$double.eps)) противIdentical(as.integer64(3e8), as.integer64(3e8*(1+.Machine$double.eps)) - то есть, нет никакой двусмысленности в следующем возможном значении .. в случае целого числа 64 это 3e8 + 1. Это определенно лучше. Похоже, пакет int64 архивируется с 2012 года.
 stanekam06 июн. 2016 г., 23:57
@Arun это также появляется изdata.table исходный код, который я могу просто добавитьinteger64 как класс к моей колонке и обойти это, все еще используя data.table. Еще раз спасибо за всю большую работуdata.table и мой вопрос!
 stanekam06 июн. 2016 г., 20:32
@Arun 64-разрядное целое число просто используется для хранения кодировки, которая вмещается в 64-разрядную версию и может использоваться для большинства языков изначально. В R это не так, и bit64 просто использует сам себя как удвоитель. Значит, они тоже их неправильно используют? Мы, вероятно, будем придерживаться использования double, чтобы не пытаться интегрироваться на уровне C с другим пакетом и переключаться на dplyr, когда это необходимо. Ура и еще раз спасибо!
 stanekam06 июн. 2016 г., 23:56
@ Арун Я думаю, что мне может быть трудно объяснить, почему мы делаем то, что делаем. У нас есть код, который берет определенные данные и создает их 64-битную кодировку, используя причудливую математику, которая позволяет нам эффективно объединять данные. В этом кодировании никогда не выполняется целочисленная математика. Мы делаем побитовые операции для кодирования / декодирования и получения других данных, но это все. Чтобы сделать эту высокую производительность в R мы используемdouble держать эти 64 бита. Все это говорит о том, что пользователи могут делать то, что вы не ожидаете, но они являются вполне допустимыми вариантами использования, поэтому я бы посоветовал не ограничивать их.

Ваш ответ на вопрос