Есть условный флаг отладки, который я пропускаю из 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 ГБ, это должно быть существенной экономией при копировании данных. Можно получить дополнительные улучшения с помощью нескольких ядер, но немного более продвинутые.