- PVSM.RU - https://www.pvsm.ru -
Тем, кто работает с R, хорошо известно, что изначально язык разрабатывался как инструмент для интерактивной работы. Естественно, что методы удобные для консольного пошагового применения человеком, который глубоко в теме, оказываются малопригодными для создания приложения для конечного пользователя. Возможность получить развернутую диагностику сразу по факту ошибки, проглядеть все переменные и трейсы, выполнить вручную элементы кода (возможно, частично изменив переменные) — все это будет недоступно при автономной работе R приложения в enterprise среде. (говорим R, подразумеваем, в основном, Shiny web приложения).
Однако, не все так плохо. Среда R (пакеты и подходы) настолько сильно эволюционировали, что ряд весьма нехитрых трюков позволяет элегантно решать задачу обеспечения стабильности и надежности работы пользовательских приложений. Ряд из них будет описан ниже.
Является продолжением предыдущих публикаций [1].
Основной спектр задач для которых часто применяется R — разнообразная обработка данных. И даже полностью отлаженный алгоритм, обложеные со всех сторон тестами и полностью задокументированный может легко сломаться и выдать ерунду, если ему на вход подсунут кривые данные.
Данные могут поступать на вход как от других информационных систем, так и от пользователей. И, если в первом случае можно требовать соблюдения API и накладывать весьма жесткие ограничения на стабильность информационного потока, то во втором случае от сюрпризов никуда не деться. Человек может ошибиться и подсунуть не тот файл, написать в него не то. 99% пользователей используют в своей работе Excel и предпочитают подсовывать системе именно его, много страничный, с хитрым форматированием. В этом случае задача еще больше усложняется. Даже визуально валидный документ может выглядеть с точки зрения машины полной ерундой. Даты разъезжаются (весьма известная история «Excel’s designer thought 1900 was a leap year, but it was not» [2]). Числовые значения хранятся как текст и наборот. Невидимые ячейки и скрытые формулы… И многое другое. Предусмотреть все возможные грабли в принципе не получится — фантазии не хватит. Чего стоит только задвоение записей в различных join-ах с кривыми источниками.
В качестве дополнительных соображенией примем следующие:
Прекрасный документ «An introduction to data cleaning with R» [3], описывающий процесс предварительной подготовки данных. Для дальнейших шагов из него мы выделим наличие двух фаз валидации: техническая и логическая.
Пойдем с конца. Для логической валидации существует ряд пакетов. В нашей практике мы остановились на следующих подходах.
dplyr
[4]. В простых случаях бывает удобно просто нарисовать pipe c проведением ряда проверок и анализом конечного результата.validate
[5] для проверки технически корректных объектов на соответствие заданным правилам.Для технической валидации остановились на следующих подходах:
checkmate
[6] с широким спектром быстрых функций для проведения разнобразных технических проверок.purr
[9] обертки для исключений. Весьма полезно при применении внутри pipe.В коде, разбитом на функции, важным элементом «defensive programming» является проверка входных и выходных параметров функций. В случае языков с динамической типизацией проверку типов приходится делать самостоятельно. Для базовых типов идеально подходит пакет checkmate, особенно его функции qtest
qassert
. Для проверки data.frame
остановились на примерно следующей конструкции (проверка имен и типов). Трюк со слиянием имени и типа позволяет сократить количество строк в проверке.
ff <- function(dataframe1, dataframe2){
# достали имя текущей функции для задач логирования
calledFun <- deparse(as.list(sys.call())[[1]])
tic("Calculating XYZ")
# проверяем содержимое всех входных дата фреймов (class, а не typeof, чтобы Date отловить)
list(dataframe1=c("name :: character", "val :: numeric", "ship_date :: Date"),
dataframe2=c("out :: character", "label :: character")) %>%
purrr::iwalk(~{
flog.info(glue::glue("Function {calledFun}: checking '{.y}' parameter with expected structure '{collapse(.x, sep=', ')}'"))
rlang::eval_bare(rlang::sym(.y)) %>%
assertDataFrame(min.rows=1, min.cols=length(.x)) %>%
{assertSetEqual(.x, stri_join(names(.), map_chr(., class), sep=" :: "), .var.name=.y)}
# {assertSubset(.x, stri_join(names(.), map_chr(., typeof), sep=" :: "))}
})
…
}
В части функции проверки типов можно выбирать метод по вкусу, сообразуясь с ожидаемыми данными. class
был выбран, поскольку именно он дает дату как Date
, а не как число (внутреннее представление). Очень подробно вопрос определения типов данных разбирается в диалоге «A comprehensive survey of the types of things in R. 'mode' and 'class' and 'typeof' are insufficient» [10].
assertSetEqual
или assertSubset
выбираются из соображений четкого совпадения колонок или же минимально достаточного.
Для практических задач такой небольшой набор вполне покрывает большую часть потребностей.
Предыдущая публикация — R как спасательный круг для системного администратора [11].
Автор: Илья Шутов
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/data-mining/282650
Ссылки в тексте:
[1] предыдущих публикаций: https://habrahabr.ru/users/i_shutov/posts/
[2] «Excel’s designer thought 1900 was a leap year, but it was not»: https://www.joelonsoftware.com/2006/06/16/my-first-billg-review/
[3] «An introduction to data cleaning with R»: https://cran.r-project.org/doc/contrib/de_Jonge+van_der_Loo-Introduction_to_data_cleaning_with_R.pdf
[4] dplyr
: https://dplyr.tidyverse.org
[5] validate
: https://cran.r-project.org/web/packages/validate/index.html
[6] checkmate
: https://cran.r-project.org/web/packages/checkmate/index.html
[7] «Advanced R. Debugging, condition handling, and defensive programming»: http://adv-r.had.co.nz/Exceptions-Debugging.html
[8] «Advanced R. Beyond Exception Handling: Conditions and Restarts»: http://adv-r.had.co.nz/beyond-exception-handling.html
[9] purr
: https://purrr.tidyverse.org
[10] «A comprehensive survey of the types of things in R. 'mode' and 'class' and 'typeof' are insufficient»: https://stackoverflow.com/questions/8855589/a-comprehensive-survey-of-the-types-of-things-in-r-mode-and-class-and-type
[11] R как спасательный круг для системного администратора: https://habr.com/post/348128/
[12] Источник: https://habr.com/post/413865/?utm_source=habrahabr&utm_medium=rss&utm_campaign=413865
Нажмите здесь для печати.