Есть условный флаг отладки, который я пропускаю из Matlab: dbstop if infnan
описанный здесь. Если установлено, это условие прекратит выполнение кода, если встречается Inf
или NaN
(IIRC, Matlab не имеет NA).
Как я могу достичь этого в R более эффективным образом, чем тестирование всех объектов после каждой операции присваивания?
В настоящий момент единственными способами, которые я вижу для этого, являются хаки, такие как:
- Вручную вставить тест после всех мест, где могут встречаться эти значения (например, деление, где может происходить деление на 0). Тестирование состояло в том, чтобы использовать
is.finite()
, описанные в этих Q и A, для каждого элемента. - Используйте
body()
для изменения кода для вызова отдельной функции после каждой операции или, возможно, только для каждого назначения, которое проверяет все объекты (и, возможно, все объекты во всех средах). - Изменить исходный код R (?!?)
- Попытайтесь использовать
tracemem
для идентификации тех переменных, которые изменились, и проверьте только эти значения для плохих значений. - (Новый - см. примечание 2) Для вызова тестовой функции используйте какие-либо обработчики/обратные вызовы.
Первый вариант - это то, что я делаю в настоящее время. Это утомительно, потому что я не могу гарантировать, что все проверил. Второй вариант будет проверять все, даже если объект не обновлен. Это огромная трата времени. Третий вариант включает модификацию присвоений NA, NaN и бесконечных значений (+/- Inf), так что возникает ошибка. Кажется, что лучше оставить R Core. Четвертый вариант похож на второй - мне нужен вызов отдельной функции, перечисляющей все ячейки памяти, только для идентификатора тех, которые изменились, и затем проверьте значения; Я даже не уверен, что это будет работать для всех объектов, так как программа может выполнять модификацию на месте, которая, похоже, не будет вызывать функцию duplicate
.
Есть ли лучший подход, который мне не хватает? Может быть, какой-то умный инструмент Марк Бравингтон, Люк Тирни или что-то относительно базовое - что-то похожее на параметр options()
или флаг при компиляции R?
Пример кода Вот какой очень простой примерный код для тестирования, включающий функцию addTaskCallback
, предложенную Джошем О'Брайеном. Код не прерывается, но ошибка возникает в первом сценарии, в то время как во втором случае ошибка не возникает (т.е. badDiv(0,0,FALSE)
не прерывается). Я все еще расследую обратные вызовы, поскольку это выглядит многообещающим.
badDiv <- function(x, y, flag){
z = x / y
if(flag == TRUE){
return(z)
} else {
return(FALSE)
}
}
addTaskCallback(stopOnNaNs)
badDiv(0, 0, TRUE)
addTaskCallback(stopOnNaNs)
badDiv(0, 0, FALSE)
Примечание 1. Я был бы удовлетворен решением для стандартных операций R, хотя многие мои вычисления связаны с объектами, используемыми через data.table
или bigmemory
(то есть на основе памяти на основе дисков). Кажется, что они имеют несколько разные типы памяти, чем стандартные операции с матрицей и data.frame.
Примечание 2. Идея обратных вызовов выглядит несколько более перспективной, так как это не требует, чтобы я записывал функции, которые мутируют R-код, например. через идею body()
.
Примечание 3. Я не знаю, есть ли какой-либо простой способ проверить наличие не конечных значений, например. метаинформация об объектах, которые индексируют, где NA, Infs и т.д. хранятся в объекте, или если они сохранены на месте. До сих пор я пробовал пакет Simon Urbanek inspect
и не нашел способ угадать наличие нечисловых значений.
Последующие действия: Саймон Урбанек отметил в комментарии, что такая информация недоступна в качестве метаинформации для объектов.
Примечание 4. Я все еще тестирую представленные идеи. Кроме того, как предложил Саймон, тестирование на наличие не конечных значений должно быть самым быстрым в C/С++; который должен превзойти даже скомпилированный R-код, но я открыт для чего угодно. Для больших наборов данных, например. порядка 10-50 ГБ, это должно быть существенной экономией при копировании данных. Можно получить дополнительные улучшения с помощью нескольких ядер, но немного более продвинутые.