sql >> Base de Datos >  >> RDS >> Sqlserver

Creación de un modelo de aprendizaje automático con SQL Server, ML.NET y C#

Este artículo es parte de la iniciativa del Cuarto Calendario Anual de Adviento de C# de Matthew D. Groves. Allí encontrará otros artículos y tutoriales útiles publicados diariamente por miembros de la comunidad y expertos, así que asegúrese de consultarlo todos los días.

ML.NET es un marco de aprendizaje automático gratuito, de código abierto y multiplataforma diseñado para desarrolladores de .NET. ML.NET le permite reutilizar todo el conocimiento, las habilidades, el código y las bibliotecas que ya tiene como desarrollador de .NET para que pueda integrar fácilmente el aprendizaje automático en sus aplicaciones web, móviles, de escritorio, juegos y IoT.

Puede aplicarlo para escenarios de clasificación, regresión, series temporales e incluso visión por computadora (aprendizaje profundo, clasificación de imágenes) con más de 40 entrenadores (algoritmos de aprendizaje automático basados ​​en tareas) a su disposición.

Desde la versión preliminar 1.4 en adelante, se admite la clase DatabaseLoader, lo que significa que ahora podemos entrenar y crear modelos directamente en bases de datos relacionales, incluidas SQL Server, Oracle, PostgreSQL, SQLite y otras.

Para este ejemplo, voy a construir un modelo que ayude a identificar si una mujer puede desarrollar diabetes en base a datos históricos de otros pacientes. Estoy usando un conjunto de datos de Kaggle que puedes descargar desde aquí.

Después de eso, cree un Paciente tabla para almacenar la información. El único requisito es utilizar un real tipo de datos para campos numéricos, ya que ML.NET solo entenderá este tipo. Otra opción es realizar una operación CAST cuando recupera los datos y convierte los campos en reales sobre la marcha .

CREATE TABLE Patient(
  Id int identity(1,1) primary key,
  Pregnancies real not null,
  Glucose real not null,
  BloodPressure real not null,
  SkinThickness real not null,
  Insulin real not null,
  BMI real not null,
  DiabetesPedigreeFunction real not null,
  Age real not null,
  Output varchar(1) not null
)

Y, por supuesto, debe insertar todos los datos del archivo csv en la tabla .

¡Ahora, escribamos algo de código!

Paso 1. Cree un nuevo proyecto de aplicación de consola C#:

Paso 2. Agregue los siguientes paquetes de Nuget a su proyecto:

  • Microsoft.ML
  • System.Data.SqlClient
  • Microsoft.Extensions.Configuration
  • Microsoft.Extensiones.Configuración.Json
  • Microsoft.Extensions.Configuration.FileExtensions

Paso 3. Agregue un archivo de configuración de la aplicación a su proyecto.

En este archivo, agregue un ConnectionStrings colección con una DbConnection elemento. El valor, por supuesto, es la cadena de conexión a la base de datos donde residen sus datos.

Por ejemplo, me conectaré a una base de datos Azure SQL :

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ConnectionStrings": {
    "DbConnection": "Server=tcp:myserver.database.windows.net,1433;Initial Catalog=mydatabase;Persist Security Info=False;User ID=myadmin;Password=MYadm1n;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
  }
}

NOTA:Establezca el Copiar en el directorio de salida propiedad para este archivo; de lo contrario, el programa no lo leerá más tarde.

Paso 4. Añadir un Modelos carpeta a su proyecto. Dentro, crea una nueva clase llamada Paciente , que incluye varias propiedades que coinciden con la estructura Table. Además, cada propiedad está decorada con LoadColumnAttribute con un índice de base cero que representa la columna que se asignará desde la tabla de la base de datos.

using Microsoft.ML.Data;

namespace DiabetesPrediction.Models
{
    public class Patient
    {
        [LoadColumn(0)]
        public float Id { get; set; }

        [LoadColumn(1)]
        public float Pregnancies { get; set; }

        [LoadColumn(2)]
        public float Glucose { get; set; }

        [LoadColumn(3)]
        public float BloodPressure { get; set; }

        [LoadColumn(4)]
        public float SkinThickness { get; set; }

        [LoadColumn(5)]
        public float Insulin { get; set; }

        [LoadColumn(6)]
        public float BMI { get; set; }

        [LoadColumn(7)]
        public float DiabetesPedigreeFunction { get; set; }

        [LoadColumn(8)]
        public float Age { get; set; }

        [LoadColumn(9)]
        public float Output { get; set; }
    }
}

Paso 5. Agregue una Predicción de diabetesML clase que hereda de Paciente e incluye propiedades adicionales. Esto se usará después de que se construya el modelo de aprendizaje automático, para mostrar los datos previstos:

using Microsoft.ML.Data;

namespace DiabetesPrediction.Models
{
    public class DiabetesMLPrediction : Patient
    {
        [ColumnName("PredictedLabel")]
        public float Prediction { get; set; }

        public float Probability { get; set; }

        public float[] Score { get; set; }
    }
}

Paso 6. En el Program.cs archivo:

una. Agregue estos espacios de nombres:

using System;
using System.IO;
using System.Linq;
using System.Data.SqlClient;

using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.Extensions.Configuration;

using DiabetesPrediction.Models;

b. Dentro de la clase, agregue un GetDbConnection método que extrae la cadena de conexión de appsettings.json expediente:

private static string GetDbConnection()
{
   var builder = new ConfigurationBuilder()
      .SetBasePath(Directory.GetCurrentDirectory())
      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

   return builder.Build().GetConnectionString("DbConnection");
}

C. En el método Principal:

  • Cree una instancia de MLContext
  • Cree una instancia de DatabaseLoader basada en la clase Paciente
  • Llamar al método GetDbConnection
  • Prepare una instrucción SQL que lea todos los datos (y convierta la identificación en un campo real)
  • Prepare una instancia de DatabaseSource que use la cadena de conexión y la declaración.
var context = new MLContext();

var loader = context.Data.CreateDatabaseLoader<Patient>();

var connectionString = GetDbConnection();

var sqlCommand = "Select CAST(Id as REAL) as Id, Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI, DiabetesPedigreeFunction, Age, CAST(Output as REAL) as Output From Patient";

var dbSource = new DatabaseSource(SqlClientFactory.Instance, connectionString, sqlCommand);
  • Cargue los datos de la tabla en un objeto IDataView y divídalos en otros dos IDataViews, uno para entrenamiento y otro para evaluación:
Console.WriteLine("Loading data from database...");
var data = loader.Load(dbSource);

var set = context.Data.TrainTestSplit(data, testFraction: 0.2);
var trainingData = set.TrainSet;
var testData = set.TestSet;
  • Cree un ITransformer preparando una canalización de capacitación que creará un modelo de aprendizaje automático BinaryClassification. Especifique la columna que se pronosticará (Salida):
Console.WriteLine("Preparing training operations...");
var pipeline = context.Transforms
       .Conversion.MapValueToKey(outputColumnName: "Label", inputColumnName: "Output")
       .Append(context.Transforms.Concatenate("Features", "Pregnancies", "Glucose", "BloodPressure", "SkinThickness", "Insulin", "BMI", "DiabetesPedigreeFunction", "Age"))
       .Append(context.MulticlassClassification.Trainers.OneVersusAll(context.BinaryClassification.Trainers.AveragedPerceptron("Label", "Features", numberOfIterations: 10))
       .Append(context.Transforms.Conversion.MapKeyToValue("PredictedLabel")));
  • Ahora, divida el conjunto de datos de entrenamiento en 10 pliegues. 9 pliegues se utilizan en el entrenamiento y el pliegue restante se utiliza para la prueba. Este proceso se repite 10 veces cambiando los conjuntos de datos de tren y prueba. Este proceso se conoce como validación cruzada de 10 veces (por supuesto, puede cambiar el número). Las métricas también se muestran:
Console.WriteLine("=============== Starting 10 fold cross validation ===============");
var crossValResults = context.MulticlassClassification.CrossValidate(data: trainingData, estimator: pipeline, numberOfFolds: 10, labelColumnName: "Label");
var metricsInMultipleFolds = crossValResults.Select(r => r.Metrics);
var microAccuracyValues = metricsInMultipleFolds.Select(m => m.MicroAccuracy);
var microAccuracyAverage = microAccuracyValues.Average();
var macroAccuracyValues = metricsInMultipleFolds.Select(m => m.MacroAccuracy);
var macroAccuracyAverage = macroAccuracyValues.Average();
var logLossValues = metricsInMultipleFolds.Select(m => m.LogLoss);
var logLossAverage = logLossValues.Average();
var logLossReductionValues = metricsInMultipleFolds.Select(m => m.LogLossReduction);
var logLossReductionAverage = logLossReductionValues.Average(); Console.WriteLine($"*************************************************************************************************************");

Console.WriteLine($"*       Metrics Multi-class Classification model      ");
Console.WriteLine($"*------------------------------------------------------------------------------------------------------------");
Console.WriteLine($"*       Average MicroAccuracy:   {microAccuracyAverage:0.###} ");
Console.WriteLine($"*       Average MacroAccuracy:    {macroAccuracyAverage:0.###} ");
Console.WriteLine($"*       Average LogLoss:          {logLossAverage:#.###} ");
Console.WriteLine($"*       Average LogLossReduction: {logLossReductionAverage:#.###} ");
Console.WriteLine($"*************************************************************************************************************");

  • A continuación, puede entrenar el modelo llamando al método Fit:
Console.WriteLine($"Training process is starting. {DateTime.Now.ToLongTimeString()}");
var model = pipeline.Fit(trainingData);
Console.WriteLine($"Training process has finished. {DateTime.Now.ToLongTimeString()}");

Este proceso lleva algo de tiempo.

  • Después de crear el modelo, puede comenzar a hacer predicciones creando un PredictionEngine y pasando un objeto Paciente al método Predict:
var predictionEngine = context.Model.CreatePredictionEngine<Patient, DiabetesMLPrediction>(model);

var patient = new Patient()
{
  Age = 42,
  BloodPressure = 81,
  BMI = 30.1f,
  DiabetesPedigreeFunction = 0.987f,
  Glucose = 120,
  Insulin = 100,
  Pregnancies = 1,
  SkinThickness = 26,
  Id = 0,
  Output = 0
};

var prediction = predictionEngine.Predict(patient);
Console.WriteLine($"Diabetes? {prediction.Output} | Prediction: {(Convert.ToBoolean(prediction.Prediction) ? "Yes" : "No")} | Probability: {prediction.Probability} ");

  • Finalmente, puede guardar el modelo para usarlo en otros proyectos (Web Api, Azure Functions, etc.)
Console.WriteLine("Saving the model");
context.Model.Save(model, trainingData.Schema, "MLModel.zip");

Paso 7. Ejecute el programa, obtendrá los resultados y un modelo ML listo para algunas predicciones:

El código está disponible en GitHub.

Espero que esta publicación de blog haya sido interesante y útil para usted. Los invito a visitar mi blog para obtener más publicaciones técnicas sobre Xamarin, Azure y el ecosistema .NET . Escribo en idioma español =)

¡Gracias por su tiempo y disfrute del resto de las publicaciones del Calendario de Adviento de C#!

Hasta la próxima,
Luis