Настройка производительности и оптимизация данных для R

Область применения: SQL Server 2016 (13.x) и более поздних версий

Эта статья описывает оптимизацию производительности для скриптов R или Python, выполняемых в SQL Server. Вы можете использовать эти методы для изменения кода R, чтобы повысить производительность и предотвратить возникновение известных проблем.

Выбор контекста вычислений

В SQL Server при выполнении скрипта R или Python можно использовать локальный контекст вычислений или контекст вычислений SQL.

При использовании локального контекста вычислений анализ выполняется на компьютере, а не на сервере. Поэтому при получении из SQL Server данных для использования в коде их нужно извлечь по сети. Снижение производительности, вызванное такой передачей по сети, зависит от объема передаваемых данных, скорости сети и других передач данных по сети, выполняемых одновременно.

При использовании контекста вычислений SQL Server код выполняется на сервере. Если данные поступают из SQL Server, они должны быть локальными по отношению к серверу, на котором выполняется анализ, благодаря чему сетевые издержки отсутствуют. Если необходимо импортировать данные из других источников, рекомендуется заранее предусмотреть извлечение, преобразование и загрузку (ETL).

При работе с большими наборами данных следует всегда использовать контекст вычислений SQL.

Факторы

В языке R используется концепция факторов, которые представляют собой специальную переменную для категориальных данных. Специалисты по обработке и анализу данных часто используют факторные переменные в своей формуле, так как обработка категориальных переменных в качестве факторов гарантирует правильную обработку данных функциями машинного обучения.

Для факторных переменных изначально предусмотрена возможность преобразования из строк в целые числа и обратно для хранения или обработки. Функция data.frame R обрабатывает все строки как факторные переменные, если только для аргумента stringsAsFactors не задано значение false. Это означает, что строки автоматически преобразуются в целое число для обработки, а затем сопоставляются с исходной строкой.

Если исходные данные для факторов хранятся в виде целого числа, производительность может снизиться, так как R преобразует целочисленные факторы в строки во время выполнения, а затем выполняет собственное внутреннее преобразование из строки в целое число.

Чтобы устранить такие преобразования во время выполнения, рекомендуется хранить значения в виде целых чисел в таблице SQL Server и использовать аргумент colInfo, чтобы указать уровни для столбца, используемого в качестве фактора. Большинство объектов источника данных в RevoScaleR принимают параметр colInfo. Используйте этот параметр, чтобы присвоить имена переменным, используемым источником данных, указать их тип и определить уровни переменных или преобразования для значений столбцов.

Например, следующий вызов функции R возвращает целые числа 1, 2 и 3 из таблицы, но сопоставляет значения с фактором с уровнями "apple", "orange" и "banana".

c("fruit" = c(type = "factor", levels=as.character(c(1:3)), newLevels=c("apple", "orange", "banana")))

Если исходный столбец содержит строки, всегда эффективнее указать уровни заранее с помощью параметра colInfo. Например, следующий код R обрабатывает строки как факторы по мере их считывания.

c("fruit" = c(type = "factor", levels= c("apple", "orange", "banana")))

Если семантические различия при создании модели отсутствуют, последний подход позволяет повысить производительность.

Преобразования данных

Специалисты по анализу и обработке данных часто используют функции преобразования, написанные на языке R, в процессе анализа. Функция преобразования применяется к каждой строке, полученной из таблицы. В SQL Server такие преобразования применяются ко всем строкам, полученным в пакете, для чего требуется обмен данными между интерпретатором R и подсистемой аналитики. Чтобы выполнить преобразование, данные перемещаются из SQL в подсистему аналитики, а затем в процесс интерпретатора R и обратно.

Поэтому использование преобразований в составе кода R может значительно снизить производительность алгоритма в зависимости от используемого объема данных.

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

Считывание строк пакета

Если в коде используется источник данных SQL Server (RxSqlServerData), рекомендуется использовать параметр rowsPerRead, чтобы указать размер пакета. Этот параметр определяет количество строк, которые запрашиваются и затем отправляются во внешний скрипт для обработки. Во время выполнения алгоритм видит только указанное число строк в каждом пакете.

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

По умолчанию для этого параметра задано значение 50 000, чтобы гарантировать хорошую производительность даже на компьютерах с недостаточным объемом памяти. Если на сервере достаточно памяти, увеличение этого значения до 500 000 или даже до миллиона может помочь повысить производительность, особенно для больших таблиц.

Преимущества увеличения размера пакета становятся очевидными для большого набора данных и для задачи, которая может выполняться в нескольких процессах. Однако увеличение этого значения не всегда дает наилучшие результаты. Для определения оптимального значения рекомендуется поэкспериментировать с данными и алгоритмом.

Параллельная обработка

Чтобы повысить производительность аналитических функций rx, можно использовать возможность параллельного выполнения задач на ядрах, доступных на серверном компьютере, в SQL Server.

Существует два способа достижения параллелизации с использованием R в SQL Server:

  • Используйте параметр @parallel. При использовании хранимой процедуры sp_execute_external_script для выполнения скрипта R установите для параметра @parallel значение 1. Это оптимальный метод, если скрипт R не использует функции RevoScaleR, которые имеют другие механизмы обработки. Если скрипт использует функции RevoScaleR (которые обычно имеют префикс "rx"), параллельная обработка выполняется автоматически, и вам не нужно явно задавать значение 1 для @parallel.

    Если скрипт R и SQL-запрос можно выполнить параллельно, ядро СУБД создает несколько параллельных процессов. Максимальное число создаваемых процессов равно значению параметра максимальной степени параллелизма (MAXDOP) для экземпляра. При этом все процессы выполняют один и тот же скрипт, но получают только часть данных.

    Таким образом, этот метод не полезен для скриптов, которые должны просматривать все данные, например при обучении модели. Тем не менее это пригодится при выполнении задач, таких как пакетное прогнозирование в параллельном режиме. Дополнительные сведения об использовании параллелизма с sp_execute_external_script см. в разделе Дополнительные советы: параллельная обработка статьи Использование кода R в Transact-SQL.

  • Используйте numTasks =1. При использовании функций rx в контексте вычислений SQL Server задайте для параметра numTasks число процессов, которые требуется создать. Число созданных процессов не может превышать значение MAXDOP, однако фактическое число создаваемых процессов определяется ядром СУБД и может быть меньше запрошенного.

    Если скрипт R и SQL-запрос можно выполнить параллельно, SQL Server создает несколько параллельных процессов при выполнении функций rx. Фактическое число создаваемых процессов зависит от различных факторов, таких как система управления ресурсами, текущее использование ресурсов, другие сеансы и план выполнения запросов для запроса, используемого со скриптом R.

Параллелизация запросов

В Microsoft R можно работать с источниками данных SQL Server, определив свои данные в качестве объекта источника данных RxSqlServerData.

Создание источника данных на основе всей таблицы или всего представления:

RxSqlServerData(table= "airline", connectionString = sqlConnString)

Создание источника данных на основе SQL-запроса:

RxSqlServerData(sqlQuery= "SELECT [ArrDelay],[CRSDepTime],[DayOfWeek] FROM  airlineWithIndex WHERE rowNum <= 100000", connectionString = sqlConnString)

Примечание.

Если в источнике данных указана таблица, а не запрос, службы R Services используют внутреннюю эвристику, чтобы определить необходимые столбцы, которые нужно извлечь из таблицы. Однако при таком подходе вряд ли произойдет параллельное выполнение.

Чтобы убедиться, что данные можно проанализировать в параллельном режиме, следует встроить запрос, используемый для извлечения данных, таким образом, чтобы ядро СУБД могло создать план параллельного выполнения запросов. Если в коде или алгоритме используются большие объемы данных, убедитесь, что запрос, передаваемый в RxSqlServerData, оптимизирован для параллельного выполнения. Запрос, который не выполняется в рамках плана параллельного выполнения, может выполниться в одном процессе для вычисления.

Если необходимо работать с большими наборами данных, то перед запуском кода R используйте Management Studio или другой анализатор SQL-запросов, чтобы проанализировать план выполнения. Затем выполните все рекомендуемые меры для повышения производительности запроса. Например, отсутствующий индекс таблицы может повлиять на время, затраченное на выполнение запроса. Дополнительные сведения см. в статье Наблюдение и настройка производительности.

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

  • Старайтесь не использовать SELECT *.
  • Проверьте столбцы в наборе данных и отберите только те из них, которые необходимы для анализа.
  • Удалите из запросов все столбцы, содержащие типы данных, несовместимые с кодом R, такие как идентификаторы GUID и rowguid.
  • Убедитесь в отсутствии неподдерживаемых форматов даты и времени.
  • Вместо загрузки таблицы создайте представление, которое выбирает определенные значения или приводит столбцы, чтобы предотвратить ошибки преобразования.

Оптимизация алгоритма машинного обучения

В этом разделе приведены различные советы и ресурсы, относящиеся к RevoScaleR и другим возможностям в Microsoft R.

Совет

Общее обсуждение оптимизации R выходит за рамки этой статьи. Тем не менее, если необходимо ускорить выполнение кода, мы рекомендуем ознакомиться с популярной статьей The R Inferno. В ней подробно описаны программные конструкции в R и распространенные ловушки, а также представлено множество примеров методов программирования R.

Оптимизации для RevoScaleR

Множество алгоритмов RevoScaleR поддерживают параметры управления созданием обученной модели. Хотя точность и правильность модели имеет большое значение, производительность алгоритма не менее важна. Чтобы должным образом сбалансировать точность и время обучения, можно изменить параметры для повышения скорости вычислений. Во многих случаях это позволяет повысить производительность, не снижая точность и правильность.

  • rxDTree

    rxDTree поддерживает параметр maxDepth, управляющий глубиной дерева принятия решений. По мере увеличения значения maxDepth возможно снижение производительности, поэтому важно проанализировать преимущества увеличения глубины в зависимости от негативного влияния на производительность.

    Можно сбалансировать временную сложность и точность прогнозирования, настроив такие параметры, как maxNumBins, maxDepth, maxComplete и maxSurrogate. Если увеличить глубину до 10 или 15, стоимость вычислений сильно увеличится.

  • rxLinMod

    Попробуйте использовать аргумент cube, если первая зависимая переменная в формуле является факторной.

    Если для параметра cube задано значение TRUE, регрессия выполняется с применением обратного секционирования. При этом операция может выполняться быстрее, а также потреблять меньше памяти, чем при стандартной регрессии. Если в формуле используется много переменных, производительность может существенно повыситься.

  • rxLogit

    Используйте аргумент cube, если первая зависимая переменная является факторной.

    Если для cube задано значение TRUE, алгоритм использует обратное секционирование, что может ускорить выполнение и снизить использование памяти. Если в формуле используется много переменных, производительность может существенно повыситься.

Подробные сведения об оптимизации RevoScaleR см. в следующих статьях:

Использование MicrosoftML

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

Следующие шаги