Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Область применения: SQL Server 2016 (13.x) и более поздних версий
В SQL Server 2019 моделирование на основе секций — это возможность создания и обучения моделей по секционированным данным. Для стратифицированных данных, которые естественным образом сегментируются в определенную классификационную схему, например по географическим регионам, дате и времени, возрасту или полу, вы можете выполнить скрипт для всего набора данных с возможностью моделирования, обучения и оценки по секциям, которые не затрагиваются всеми этими операциями.
Моделирование на основе секций включается с помощью следующих двух новых параметров в sp_execute_external_script.
-
input_data_1_partition_by_columns— указывает столбец для секционирования по. -
input_data_1_order_by_columnsуказывает, по каким столбцам следует упорядочивать.
В этом руководстве рассматривается моделирование на основе секций с использованием классической выборки данных о работе такси в Нью-Йорке и скрипта R. Столбец секционирования — метод оплаты.
- Построение секций по типам платежей (5).
- Создание и обучение моделей в каждой секции и сохранение объектов в базе данных.
- Прогнозирование вероятности исходов по каждой модели секционирования с использованием выборочных данных, зарезервированных для этой цели.
Необходимые компоненты
Для работы с этим учебником необходимо наличие следующих компонентов.
Достаточное количество системных ресурсов. Так как работа выполняется на большом наборе данных, операции обучения требуют много ресурсов. По возможности используйте систему с не менее 8 ГБ ОЗУ. Можно также попробовать использовать меньшие наборы данных, чтобы обойти ресурсные ограничения. Следуйте встроенным инструкциям по сокращению набора данных.
Средство выполнения запросов T-SQL, например SQL Server Management Studio (SSMS).
NYCTaxi_Sample.bak, который можно скачать и восстановить в локальный экземпляр SQL Server. Размер файла составляет приблизительно 90 МБ.
Экземпляр ядра СУБД SQL Server 2019 со службами машинного обучения и интеграцией R.
В этом руководстве используется петлевое соединение, устанавливаемое с SQL Server из сценария R через ODBC. Поэтому необходимо создать имя входа для SQLRUserGroup.
Проверьте доступность пакетов R путем получения правильно отформатированного списка всех пакетов R, установленных в текущий момент с вашим экземпляром ядра СУБД:
EXECUTE sp_execute_external_script
@language=N'R',
@script = N'str(OutputDataSet);
packagematrix <- installed.packages();
Name <- packagematrix[,1];
Version <- packagematrix[,3];
OutputDataSet <- data.frame(Name, Version);',
@input_data_1 = N''
WITH RESULT SETS ((PackageName nvarchar(250), PackageVersion nvarchar(max) ))
Подключение к базе данных
Запустите SSMS и подключитесь к экземпляру ядра СУБД. В обозреватель объектов убедитесь, что база данных NYCTaxi_Sample существует.
Создание функции CalculateDistance
Демонстрационная база данных предоставляется со скалярной функцией для вычисления расстояния, но наша хранимая процедура лучше работает с функцией с табличным значением. Выполните следующий сценарий, чтобы создать CalculateDistance функцию, используемую на шаге обучения позже.
Чтобы подтвердить, что функция была создана, в обозреватель объектов проверьте базу \Programmability\Functions\Table-valued FunctionsNYCTaxi_Sample данных.
USE NYCTaxi_sample
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[CalculateDistance] (
@Lat1 FLOAT
,@Long1 FLOAT
,@Lat2 FLOAT
,@Long2 FLOAT
)
-- User-defined function calculates the direct distance between two geographical coordinates.
RETURNS TABLE
AS
RETURN
SELECT COALESCE(3958.75 * ATAN(SQRT(1 - POWER(t.distance, 2)) / nullif(t.distance, 0)), 0) AS direct_distance
FROM (
VALUES (CAST((SIN(@Lat1 / 57.2958) * SIN(@Lat2 / 57.2958)) + (COS(@Lat1 / 57.2958) * COS(@Lat2 / 57.2958) * COS((@Long2 / 57.2958) - (@Long1 / 57.2958))) AS DECIMAL(28, 10)))
) AS t(distance)
GO
Определение процедуры создания и обучения моделей для отдельных секций
В этом учебнике сценарий R заключается в хранимую процедуру. На этом шаге создается хранимая процедура, которая с использованием R создает входной набор данных, строит модель классификации для прогнозирования результатов, а затем сохраняет эту модель в базе данных.
Среди входных данных параметров, используемых этим скриптом, вы увидите input_data_1_partition_by_columns и input_data_1_order_by_columns. Напомним, что эти параметры и есть механизм, с помощью которого создается секционированное моделирование. Эти параметры передаются в качестве входных данных в sp_execute_external_script для обработки секций с помощью данного внешнего скрипта, который выполняется один раз для каждой секции.
Чтобы эта хранимая процедура выполнялась быстрее, используйте параллелизм.
После запуска этого скрипта в обозреватель объектов вы увидите train_rxLogIt_per_partition\Programmability\Stored Procedures в NYCTaxi_Sample базе данных. Вы также увидите новую таблицу, используемую для хранения моделей: dbo.nyctaxi_models
USE NYCTaxi_Sample
GO
CREATE
OR
ALTER PROCEDURE [dbo].[train_rxLogIt_per_partition] (@input_query NVARCHAR(max))
AS
BEGIN
DECLARE @start DATETIME2 = SYSDATETIME()
,@model_generation_duration FLOAT
,@model VARBINARY(max)
,@instance_name NVARCHAR(100) = @@SERVERNAME
,@database_name NVARCHAR(128) = db_name();
EXEC sp_execute_external_script @language = N'R'
,@script =
N'
# Make sure InputDataSet is not empty. In parallel mode, if one thread gets zero data, an error occurs
if (nrow(InputDataSet) > 0) {
# Define the connection string
connStr <- paste("Driver=SQL Server;Server=", instance_name, ";Database=", database_name, ";Trusted_Connection=true;", sep="");
# build classification model to predict a tip outcome
duration <- system.time(logitObj <- rxLogit(tipped ~ passenger_count + trip_distance + trip_time_in_secs + direct_distance, data = InputDataSet))[3];
# First, serialize a model to and put it into a database table
modelbin <- as.raw(serialize(logitObj, NULL));
# Create the data source. To reduce data size, add rowsPerRead=500000 to cut the dataset by half.
ds <- RxOdbcData(table="ml_models", connectionString=connStr);
# Store the model in the database
model_name <- paste0("nyctaxi.", InputDataSet[1,]$payment_type);
rxWriteObject(ds, model_name, modelbin, version = "v1",
keyName = "model_name", valueName = "model_object", versionName = "model_version", overwrite = TRUE, serialize = FALSE);
}
'
,@input_data_1 = @input_query
,@input_data_1_partition_by_columns = N'payment_type'
,@input_data_1_order_by_columns = N'passenger_count'
,@parallel = 1
,@params = N'@instance_name nvarchar(100), @database_name nvarchar(128)'
,@instance_name = @instance_name
,@database_name = @database_name
WITH RESULT SETS NONE
END;
GO
Параллельное выполнение
Обратите внимание, что среди входных данных для скрипта sp_execute_external_script имеется параметр @parallel=1. Он используется для включения параллельной обработки. В отличие от предыдущих выпусков, начиная с SQL Server 2019, параметр @parallel=1 обеспечивает более строгий намек на оптимизатор запросов, что делает параллельное выполнение гораздо более вероятным результатом.
По умолчанию в рамках @parallel=1 оптимизатор запросов стремится работать в таблицах, имеющих более 256 строк, но это можно задать явно, установив @parallel=1, как показано в данном скрипте.
Совет
Для обучения рабочих нагрузок можно использовать @parallel с любым произвольным скриптом обучения, даже с использованием алгоритмов, отличных от Microsoft-rx. Как правило, в SQL Server параллелизм в скриптах обучения предусмотрен только в алгоритмах RevoScaleR (с префиксом RX). Но с помощью нового параметра можно параллелизовать скрипт, который вызывает функции, не разрабатывавшиеся специально с включением этой возможности (в том числе функции R с открытым исходным кодом). Это работает потому, что секции имеют сходство с конкретными потоками, поэтому все операции, вызываемые в скрипте, выполняются на основе каждого раздела в заданном потоке.
Выполнение процедуры и обучение модели
В этом разделе скрипт обучает модель, созданную и сохраненную на предыдущем шаге. В приведенных ниже примерах демонстрируются два подхода к обучению модели: с использованием всего набора данных или частичных данных.
Ожидайте, что этот шаг займет некоторое время. Обучение требует больших вычислительных ресурсов и выполняется много минут. Если системных ресурсов, в особенности памяти, недостаточно для этой нагрузки, используйте подмножество данных. Во втором примере показан синтаксис.
--Example 1: train on entire dataset
EXEC train_rxLogIt_per_partition N'
SELECT payment_type, tipped, passenger_count, trip_time_in_secs, trip_distance, d.direct_distance
FROM dbo.nyctaxi_sample CROSS APPLY [CalculateDistance](pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude) as d
';
GO
--Example 2: Train on 20 percent of the dataset to expedite processing.
EXEC train_rxLogIt_per_partition N'
SELECT tipped, payment_type, passenger_count, trip_time_in_secs, trip_distance, d.direct_distance
FROM dbo.nyctaxi_sample TABLESAMPLE (20 PERCENT) REPEATABLE (98074)
CROSS APPLY [CalculateDistance](pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude) as d
';
GO
Примечание.
Если одновременно выполняются и другие рабочие нагрузки, можно ограничить до двух число ядер, используемых для обработки запросов, добавив OPTION(MAXDOP 2) в инструкцию SELECT.
Проверка результатов
В результате в таблице models должно появиться пять разных моделей, основанных на пяти секциях, сегментированных по пяти типам платежей. Модели находятся в источнике ml_models данных.
SELECT *
FROM ml_models
Задание процедуры для прогнозирования результатов
Для оценки можно использовать те же параметры. В следующем примере приведен скрипт R, оценивающий использование правильной модели для секции, которая в данный момент обрабатывается.
Как и ранее, создайте хранимую процедуру для включение в нее кода R.
USE NYCTaxi_Sample
GO
-- Stored procedure that scores per partition.
-- Depending on the partition being processed, a model specific to that partition will be used
CREATE
OR
ALTER PROCEDURE [dbo].[predict_per_partition]
AS
BEGIN
DECLARE @predict_duration FLOAT
,@instance_name NVARCHAR(100) = @@SERVERNAME
,@database_name NVARCHAR(128) = db_name()
,@input_query NVARCHAR(max);
SET @input_query = 'SELECT tipped, passenger_count, trip_time_in_secs, trip_distance, d.direct_distance, payment_type
FROM dbo.nyctaxi_sample TABLESAMPLE (1 PERCENT) REPEATABLE (98074)
CROSS APPLY [CalculateDistance](pickup_latitude, pickup_longitude, dropoff_latitude, dropoff_longitude) as d'
EXEC sp_execute_external_script @language = N'R'
,@script =
N'
if (nrow(InputDataSet) > 0) {
#Get the partition that is currently being processed
current_partition <- InputDataSet[1,]$payment_type;
#Create the SQL query to select the right model
query_getModel <- paste0("select model_object from ml_models where model_name = ", "''", "nyctaxi.",InputDataSet[1,]$payment_type,"''", ";")
# Define the connection string
connStr <- paste("Driver=SQL Server;Server=", instance_name, ";Database=", database_name, ";Trusted_Connection=true;", sep="");
#Define data source to use for getting the model
ds <- RxOdbcData(sqlQuery = query_getModel, connectionString = connStr)
# Load the model
modelbin <- rxReadObject(ds, deserialize = FALSE)
# unserialize model
logitObj <- unserialize(modelbin);
# predict tipped or not based on model
predictions <- rxPredict(logitObj, data = InputDataSet, overwrite = TRUE, type = "response", writeModelVars = TRUE
, extraVarsToWrite = c("payment_type"));
OutputDataSet <- predictions
} else {
OutputDataSet <- data.frame(integer(), InputDataSet[,]);
}
'
,@input_data_1 = @input_query
,@parallel = 1
,@input_data_1_partition_by_columns = N'payment_type'
,@params = N'@instance_name nvarchar(100), @database_name nvarchar(128)'
,@instance_name = @instance_name
,@database_name = @database_name
WITH RESULT SETS((
tipped_Pred INT
,payment_type VARCHAR(5)
,tipped INT
,passenger_count INT
,trip_distance FLOAT
,trip_time_in_secs INT
,direct_distance FLOAT
));
END;
GO
Создание таблицы для хранения прогнозов
CREATE TABLE prediction_results (
tipped_Pred INT
,payment_type VARCHAR(5)
,tipped INT
,passenger_count INT
,trip_distance FLOAT
,trip_time_in_secs INT
,direct_distance FLOAT
);
TRUNCATE TABLE prediction_results
GO
Выполнение процедуры и сохранение прогнозов
INSERT INTO prediction_results (
tipped_Pred
,payment_type
,tipped
,passenger_count
,trip_distance
,trip_time_in_secs
,direct_distance
)
EXECUTE [predict_per_partition]
GO
Просмотр прогнозов
Так как прогнозы сохраняются, можно выполнить простой запрос для возврата результатов.
SELECT *
FROM prediction_results;
Следующие шаги
- В этом руководстве вы использовали скрипт sp_execute_external_script для выполнения цикла операций по секционированным данным. Более подробно вызов внешних скриптов в хранимых процедурах и использование функций RevoScaleR рассматривается в следующем учебнике.