Tutorial do Python: Executar previsões usando o Python inserido em um procedimento armazenado

Aplica-se a: SQL Server 2017 (14.x) e versões posteriores da Instância Gerenciada de SQL do Azure

Na quinta parte desta série de tutoriais em cinco partes, você aprenderá a operacionalizar os modelos treinados e salvos na parte anterior.

Nesse cenário, operacionalização significa implantar o modelo em produção para pontuação. A integração ao SQL Server torna isso razoavelmente fácil, pois você pode inserir o código Python em um procedimento armazenado. Para obter previsões do modelo com base em novas entradas, basta chamar o procedimento armazenado de um aplicativo e passar os novos dados.

Esta parte do tutorial demonstra dois métodos para criar previsões com base em um modelo do Python: pontuação em lote e pontuação linha a linha.

  • Pontuação em lote: Para fornecer várias linhas de dados de entrada, passe uma consulta SELECT como argumento para o procedimento armazenado. O resultado é uma tabela de observações correspondentes aos casos de entrada.
  • Pontuação individual: Passe um conjunto de valores de parâmetro individuais como entrada. O procedimento armazenado retorna uma única linha ou valor.

todo o código Python necessário para pontuação é fornecido como parte dos procedimentos armazenados.

Neste artigo, você vai:

  • Criar e usar procedimentos armazenados para executar a pontuação em lote
  • Criar e usar procedimentos armazenados para pontuar uma única linha

Na parte um, você instalou os pré-requisitos e restaurou o banco de dados de exemplo.

Na parte dois, você explorou os dados de exemplo e gerou alguns gráficos.

Na parte três, você aprendeu a criar recursos a partir de dados brutos usando uma função do Transact-SQL. Em seguida, você chamou essa função por meio de um procedimento armazenado para criar uma tabela que contém os valores de recurso.

Na parte quatro, você carregou os módulos e chamou as funções necessárias para criar e treinar o modelo usando um procedimento armazenado do SQL Server.

Pontuação em lote

Os dois primeiros procedimentos armazenados criados usando os scripts a seguir ilustram a sintaxe básica para encapsular uma chamada de previsão do Python em um procedimento armazenado. Ambos os procedimentos armazenados exigem uma tabela de dados como entradas.

  • O nome do modelo a ser usado é fornecido como parâmetro de entrada para o procedimento armazenado. O procedimento armazenado carrega o modelo serializado da tabela de banco de dados nyc_taxi_models.table usando a instrução SELECT no procedimento armazenado.

  • O modelo serializado é armazenado na variável do Python mod para processamento adicional usando o Python.

  • Os novos casos que precisam ser pontuados são obtidos da consulta Transact-SQL especificada em @input_data_1. Conforme os dados da consulta são lidos, as linhas são salvas no quadro de dados padrão, InputDataSet.

  • Ambos os procedimentos armazenados usam funções de sklearn para calcular uma métrica de acurácia, AUC (área sob a curva). As métricas de acurácia, como AUC, só podem ser geradas se você também fornecer o rótulo de destino (a coluna tipped). As previsões não precisam do rótulo alvo (variável y), mas o cálculo da métrica de acurácia exige esse rótulo.

    Portanto, se você não tiver rótulos de destino para os dados a serem pontuados, poderá modificar o procedimento armazenado para remover os cálculos de AUC e retornar apenas as probabilidades de gorjeta dos recursos (variável X no procedimento armazenado).

PredictTipSciKitPy

Execute as instruções do T-SQL a seguir para criar o procedimento armazenado PredictTipSciKitPy. Este procedimento armazenado exige um modelo baseado no pacote scikit-learn, pois usa funções específicas para o pacote.

O quadro de dados que contém entradas é passado para a função predict_proba do modelo de regressão logística, mod. A função predict_proba (probArray = mod.predict_proba(X)) retorna um float que representa a probabilidade de uma gorjeta ser dada (de qualquer valor).

DROP PROCEDURE IF EXISTS PredictTipSciKitPy;
GO

CREATE PROCEDURE [dbo].[PredictTipSciKitPy] (@model varchar(50), @inquery nvarchar(max))
AS
BEGIN
DECLARE @lmodel2 varbinary(max) = (select model from nyc_taxi_models where name = @model);
EXEC sp_execute_external_script
  @language = N'Python',
  @script = N'
import pickle;
import numpy;
from sklearn import metrics

mod = pickle.loads(lmodel2)
X = InputDataSet[["passenger_count", "trip_distance", "trip_time_in_secs", "direct_distance"]]
y = numpy.ravel(InputDataSet[["tipped"]])

probArray = mod.predict_proba(X)
probList = []
for i in range(len(probArray)):
  probList.append((probArray[i])[1])

probArray = numpy.asarray(probList)
fpr, tpr, thresholds = metrics.roc_curve(y, probArray)
aucResult = metrics.auc(fpr, tpr)
print ("AUC on testing data is: " + str(aucResult))

OutputDataSet = pandas.DataFrame(data = probList, columns = ["predictions"])
',	
  @input_data_1 = @inquery,
  @input_data_1_name = N'InputDataSet',
  @params = N'@lmodel2 varbinary(max)',
  @lmodel2 = @lmodel2
WITH RESULT SETS ((Score float));
END
GO

PredictTipRxPy

Execute as instruções do T-SQL a seguir para criar o procedimento armazenado PredictTipRxPy. Esse procedimento armazenado usa as mesmas entradas e cria o mesmo tipo de pontuação que o procedimento armazenado anterior, mas usa funções do pacote revoscalepy fornecido com o aprendizado de máquina do SQL Server.

DROP PROCEDURE IF EXISTS PredictTipRxPy;
GO

CREATE PROCEDURE [dbo].[PredictTipRxPy] (@model varchar(50), @inquery nvarchar(max))
AS
BEGIN
DECLARE @lmodel2 varbinary(max) = (select model from nyc_taxi_models where name = @model);
EXEC sp_execute_external_script 
  @language = N'Python',
  @script = N'
import pickle;
import numpy;
from sklearn import metrics
from revoscalepy.functions.RxPredict import rx_predict;

mod = pickle.loads(lmodel2)
X = InputDataSet[["passenger_count", "trip_distance", "trip_time_in_secs", "direct_distance"]]
y = numpy.ravel(InputDataSet[["tipped"]])

probArray = rx_predict(mod, X)
probList = probArray["tipped_Pred"].values 

probArray = numpy.asarray(probList)
fpr, tpr, thresholds = metrics.roc_curve(y, probArray)
aucResult = metrics.auc(fpr, tpr)
print ("AUC on testing data is: " + str(aucResult))

OutputDataSet = pandas.DataFrame(data = probList, columns = ["predictions"])
',
  @input_data_1 = @inquery,
  @input_data_1_name = N'InputDataSet',
  @params = N'@lmodel2 varbinary(max)',
  @lmodel2 = @lmodel2
WITH RESULT SETS ((Score float));
END
GO

Executar pontuação em lote usando uma consulta SELECT

Os procedimentos armazenados PredictTipSciKitPy e PredictTipRxPy exigem dois parâmetros de entrada:

  • A consulta que recupera os dados para pontuação
  • O nome de um modelo treinado

Ao passar esses argumentos para o procedimento armazenado, você pode selecionar um modelo específico ou alterar os dados usados para pontuação.

  1. Para usar o modelo Scikit-learn para pontuação, chame o procedimento armazenado PredictTipSciKitPy, passando o nome do modelo e a cadeia de consulta como entradas.

    DECLARE @query_string nvarchar(max) -- Specify input query
      SET @query_string='
      select tipped, fare_amount, passenger_count, trip_time_in_secs, trip_distance,
      dbo.fnCalculateDistance(pickup_latitude, pickup_longitude,  dropoff_latitude, dropoff_longitude) as direct_distance
      from nyctaxi_sample_testing'
    EXEC [dbo].[PredictTipSciKitPy] 'SciKit_model', @query_string;
    

    O procedimento armazenado retorna probabilidades previstas para cada viagem que foi incluída como parte da consulta de entrada.

    Se você estiver usando o SSMS (SQL Server Management Studio) para executar consultas, as probabilidades serão exibidas como uma tabela no painel Resultados. O painel Mensagens gera a métrica de precisão (AUC ou área sob a curva) com um valor de cerca de 0,56.

  2. Para usar o modelo revoscalepy para pontuação, chame o procedimento armazenado PredictTipRxPy, passando o nome do modelo e a cadeia de consulta como entradas.

    DECLARE @query_string nvarchar(max) -- Specify input query
      SET @query_string='
      select tipped, fare_amount, passenger_count, trip_time_in_secs, trip_distance,
      dbo.fnCalculateDistance(pickup_latitude, pickup_longitude,  dropoff_latitude, dropoff_longitude) as direct_distance
      from nyctaxi_sample_testing'
    EXEC [dbo].[PredictTipRxPy] 'revoscalepy_model', @query_string;
    

Pontuação de linha única

Às vezes, em vez de pontuação em lote, você pode querer enviar um único caso, recebendo valores de um aplicativo e retornar um único resultado com base nesses valores. Por exemplo, você poderá definir uma planilha do Excel, um aplicativo Web ou um relatório para chamar o procedimento armazenado e passá-lo a ele entradas digitadas ou selecionadas por usuários.

Nesta seção, você aprenderá a criar previsões únicas chamando dois procedimentos armazenados:

  • PredictTipSingleModeSciKitPy foi projetado para a pontuação de uma única linha usando o modelo Scikit-learn.
  • PredictTipSingleModeRxPy foi projetado para a pontuação de uma única linha usando o modelo revoscalepy.
  • Se você ainda não tiver treinado um modelo, volte para parte 5.

Ambos os modelos utilizam como entrada uma série de valores únicos, como contagem de passageiros, distância da corrida e assim por diante. Uma função com valor de tabela, fnEngineerFeatures, é usada para converter valores de latitude e longitude das entradas em um novo recurso, distância direta. A parte quatro contém uma descrição dessa função com valor de tabela.

Ambos os procedimentos armazenados criam uma pontuação com base no modelo do Python.

Observação

É importante que você forneça todos os recursos de entrada exigidos pelo modelo do Python ao chamar o procedimento armazenado a partir de um aplicativo externo. Para evitar erros, pode ser necessário converter os dados de entrada em um tipo de dados do Python, além de validar o tipo de dados e o comprimento dos dados.

PredictTipSingleModeSciKitPy

O procedimento armazenado a seguir PredictTipSingleModeSciKitPy realiza a pontuação usando o modelo scikit-learn.

DROP PROCEDURE IF EXISTS PredictTipSingleModeSciKitPy;
GO

CREATE PROCEDURE [dbo].[PredictTipSingleModeSciKitPy] (@model varchar(50), @passenger_count int = 0,
  @trip_distance float = 0,
  @trip_time_in_secs int = 0,
  @pickup_latitude float = 0,
  @pickup_longitude float = 0,
  @dropoff_latitude float = 0,
  @dropoff_longitude float = 0)
AS
BEGIN
  DECLARE @inquery nvarchar(max) = N'
  SELECT * FROM [dbo].[fnEngineerFeatures]( 
    @passenger_count,
    @trip_distance,
    @trip_time_in_secs,
    @pickup_latitude,
    @pickup_longitude,
    @dropoff_latitude,
    @dropoff_longitude)
    '
DECLARE @lmodel2 varbinary(max) = (select model from nyc_taxi_models where name = @model);
EXEC sp_execute_external_script 
  @language = N'Python',
  @script = N'
import pickle;
import numpy;

# Load model and unserialize
mod = pickle.loads(model)

# Get features for scoring from input data
X = InputDataSet[["passenger_count", "trip_distance", "trip_time_in_secs", "direct_distance"]]

# Score data to get tip prediction probability as a list (of float)
probList = []
probList.append((mod.predict_proba(X)[0])[1])

# Create output data frame
OutputDataSet = pandas.DataFrame(data = probList, columns = ["predictions"])
',
  @input_data_1 = @inquery,
  @params = N'@model varbinary(max),@passenger_count int,@trip_distance float,
    @trip_time_in_secs int ,
    @pickup_latitude float ,
    @pickup_longitude float ,
    @dropoff_latitude float ,
    @dropoff_longitude float',
    @model = @lmodel2,
    @passenger_count =@passenger_count ,
    @trip_distance=@trip_distance,
    @trip_time_in_secs=@trip_time_in_secs,
    @pickup_latitude=@pickup_latitude,
    @pickup_longitude=@pickup_longitude,
    @dropoff_latitude=@dropoff_latitude,
    @dropoff_longitude=@dropoff_longitude
WITH RESULT SETS ((Score float));
END
GO

PredictTipSingleModeRxPy

O procedimento armazenado a seguir PredictTipSingleModeRxPy executa a pontuação usando o modelo revoscalepy.

DROP PROCEDURE IF EXISTS PredictTipSingleModeRxPy;
GO

CREATE PROCEDURE [dbo].[PredictTipSingleModeRxPy] (@model varchar(50), @passenger_count int = 0,
  @trip_distance float = 0,
  @trip_time_in_secs int = 0,
  @pickup_latitude float = 0,
  @pickup_longitude float = 0,
  @dropoff_latitude float = 0,
  @dropoff_longitude float = 0)
AS
BEGIN
DECLARE @inquery nvarchar(max) = N'
  SELECT * FROM [dbo].[fnEngineerFeatures]( 
    @passenger_count,
    @trip_distance,
    @trip_time_in_secs,
    @pickup_latitude,
    @pickup_longitude,
    @dropoff_latitude,
    @dropoff_longitude)
  '
DECLARE @lmodel2 varbinary(max) = (select model from nyc_taxi_models where name = @model);
EXEC sp_execute_external_script 
  @language = N'Python',
  @script = N'
import pickle;
import numpy;
from revoscalepy.functions.RxPredict import rx_predict;

# Load model and unserialize
mod = pickle.loads(model)

# Get features for scoring from input data
X = InputDataSet[["passenger_count", "trip_distance", "trip_time_in_secs", "direct_distance"]]

# Score data to get tip prediction probability as a list (of float)

probArray = rx_predict(mod, X)

probList = []
probList = probArray["tipped_Pred"].values

# Create output data frame
OutputDataSet = pandas.DataFrame(data = probList, columns = ["predictions"])
',
  @input_data_1 = @inquery,
  @params = N'@model varbinary(max),@passenger_count int,@trip_distance float,
    @trip_time_in_secs int ,
    @pickup_latitude float ,
    @pickup_longitude float ,
    @dropoff_latitude float ,
    @dropoff_longitude float',
    @model = @lmodel2,
    @passenger_count =@passenger_count ,
    @trip_distance=@trip_distance,
    @trip_time_in_secs=@trip_time_in_secs,
    @pickup_latitude=@pickup_latitude,
    @pickup_longitude=@pickup_longitude,
    @dropoff_latitude=@dropoff_latitude,
    @dropoff_longitude=@dropoff_longitude
WITH RESULT SETS ((Score float));
END
GO

Gerar pontuações de modelos

Depois da criação dos procedimentos armazenados, é fácil gerar uma pontuação com base em qualquer um dos modelos. Abra uma nova janela de Consulta e forneça os parâmetros para cada uma das colunas do recurso.

Os sete valores obrigatórios para estas colunas de recursos são, na ordem:

  • passenger_count
  • trip_distance
  • tempo_da_viagem_em_segundos
  • pickup_latitude
  • pickup_longitude
  • dropoff_latitude
  • dropoff_longitude

Por exemplo:

  • Para gerar uma previsão usando o modelo revoscalepy, execute esta instrução:

    EXEC [dbo].[PredictTipSingleModeRxPy] 'revoscalepy_model', 1, 2.5, 631, 40.763958,-73.973373, 40.782139,-73.977303
    
  • Para gerar uma pontuação usando o modelo Scikit-Learn, execute esta instrução:

    EXEC [dbo].[PredictTipSingleModeSciKitPy] 'SciKit_model', 1, 2.5, 631, 40.763958,-73.973373, 40.782139,-73.977303
    

O resultado de ambos os procedimentos é a probabilidade de pagamento de gorjeta na corrida de táxi com os parâmetros ou características especificados.

Conclusão

Nesta série de tutoriais, você aprendeu a trabalhar com código do Python integrado em procedimentos armazenados. A integração com o Transact-SQL torna muito mais fácil a implantação de modelos do Python para previsão e incorporação do novo treinamento do modelo como parte de um fluxo de trabalho de dados empresariais.