Preparación de los datos para crear un modelo
Aprenda a usar ML.NET para preparar los datos para un procesamiento adicional o para crear un modelo.
Los datos a menudo no son limpios y dispersos. ML.NET los algoritmos de aprendizaje automático esperan que la entrada o las características estén en un único vector numérico. Del mismo modo, el valor que se va a predecir (etiqueta), especialmente cuando se trata de datos categóricos, debe codificarse. Por lo tanto, uno de los objetivos de la preparación de datos es obtener los datos en el formato esperado por ML.NET algoritmos.
División de los datos en conjuntos de entrenamiento y prueba
En la sección siguiente se describen los problemas comunes al entrenar un modelo conocido como sobreajuste y infraajuste. Dividir los datos y validar los modelos mediante un conjunto mantenido puede ayudarle a identificar y mitigar estos problemas.
Sobreajuste e infraajuste
El sobreajuste y el subajuste son los dos problemas más comunes que se encuentran al entrenar un modelo. El subajuste significa que el entrenador seleccionado no es capaz de ajustarse adecuadamente al conjunto de datos de entrenamiento y normalmente da lugar a una pérdida alta durante el entrenamiento y a una puntuación o métrica baja en el conjunto de datos de prueba. Para resolverlo, debe seleccionar un modelo más eficaz o realizar más ingeniería de características. El sobreajuste es lo contrario, lo que sucede cuando el modelo aprende demasiado bien los datos de entrenamiento. Esto suele producir una métrica de baja pérdida durante el entrenamiento, pero una pérdida alta en el conjunto de datos de prueba.
Una buena analogía para estos conceptos es estudiar un examen. Supongamos que conocía las preguntas y respuestas con antelación. Después de estudiar, toma la prueba y obtiene una puntuación perfecta. ¡Buenas noticias! Sin embargo, cuando se le vuelva a dar el examen con las preguntas reorganizadas y con un texto ligeramente diferente, obtendrá una puntuación inferior. Eso sugiere que memorizaste las respuestas y no aprendiste realmente los conceptos en los que estabas probando. Este es un ejemplo de sobreajuste. El infraajuste es lo contrario, cuando los materiales de estudio que se le han dado no representan con precisión lo que se evalúa en el examen. Como resultado, recurre a adivinar las respuestas, ya que no tiene suficiente conocimiento para responder correctamente.
División de los datos
Tome los siguientes datos de entrada y cárgelos en un IDataView
denominado data
:
var homeDataList = new HomeData[]
{
new()
{
NumberOfBedrooms = 1f,
Price = 100_000f
},
new()
{
NumberOfBedrooms = 2f,
Price = 300_000f
},
new()
{
NumberOfBedrooms = 6f,
Price = 600_000f
},
new()
{
NumberOfBedrooms = 3f,
Price = 300_000f
},
new()
{
NumberOfBedrooms = 2f,
Price = 200_000f
}
};
Para dividir los datos en conjuntos de entrenamiento y pruebas, use el método TrainTestSplit(IDataView, Double, String, Nullable<Int32>).
// Apply filter
TrainTestData dataSplit = mlContext.Data.TrainTestSplit(data, testFraction: 0.2);
El parámetro testFraction
se usa para tomar 0,2 o 20% del conjunto de datos para realizar pruebas. El 80 % restante se usa para el entrenamiento.
El resultado es DataOperationsCatalog.TrainTestData con dos IDataViews a los que puede acceder a través de TrainSet y TestSet.
Filtrar datos
A veces, no todos los datos de un conjunto de datos son relevantes para el análisis. Un enfoque para quitar datos irrelevantes es el filtrado. El DataOperationsCatalog
contiene un conjunto de operaciones de filtro que toman una IDataView
que contiene todos los datos y devuelven un IDataView que contiene solo los puntos de datos de interés. Es importante tener en cuenta que dado que las operaciones de filtro no son un IEstimator
o un ITransformer
como las de TransformsCatalog
, no pueden incluirse como parte de una canalización de preparación de datos de EstimatorChain
o TransformerChain
.
Tome los siguientes datos de entrada y cárgelos en un IDataView
denominado data
:
HomeData[] homeDataList = new HomeData[]
{
new ()
{
NumberOfBedrooms=1f,
Price=100000f
},
new ()
{
NumberOfBedrooms=2f,
Price=300000f
},
new ()
{
NumberOfBedrooms=6f,
Price=600000f
}
};
Para filtrar los datos en función del valor de una columna, use el método FilterRowsByColumn
.
// Apply filter
IDataView filteredData = mlContext.Data.FilterRowsByColumn(data, "Price", lowerBound: 200000, upperBound: 1000000);
El ejemplo anterior toma filas en el conjunto de datos con un precio entre 200000 y 10000000. El resultado de aplicar este filtro devolvería solo las dos últimas filas de los datos y excluiría la primera fila porque su precio es 100000 y no entre el intervalo especificado.
Reemplazar los valores que faltan
Los valores que faltan son una aparición común en los conjuntos de datos. Un enfoque para tratar con los valores que faltan es reemplazarlos por el valor predeterminado del tipo especificado si existe u otro valor significativo, como el valor medio de los datos.
Tome los siguientes datos de entrada y cárgelos en un IDataView
denominado data
:
HomeData[] homeDataList = new HomeData[]
{
new ()
{
NumberOfBedrooms=1f,
Price=100000f
},
new ()
{
NumberOfBedrooms=2f,
Price=300000f
},
new ()
{
NumberOfBedrooms=6f,
Price=float.NaN
}
};
Observe que el último elemento de la lista tiene un valor que falta para Price
. Para reemplazar los valores que faltan en la columna Price
, use el método ReplaceMissingValues
para rellenar ese valor que falta.
Importante
ReplaceMissingValue
solo funciona con datos numéricos.
// Define replacement estimator
var replacementEstimator = mlContext.Transforms.ReplaceMissingValues("Price", replacementMode: MissingValueReplacingEstimator.ReplacementMode.Mean);
// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer replacementTransformer = replacementEstimator.Fit(data);
// Transform data
IDataView transformedData = replacementTransformer.Transform(data);
ML.NET admite varios modos de reemplazo de . En el ejemplo anterior se usa el modo de reemplazo Mean
, que rellena el valor que falta con el valor medio de esa columna. El resultado del reemplazo se rellena en la propiedad Price
para el último elemento en los datos con 200 000, ya que es la media de 100 000 y 300 000.
Uso de normalizadores
normalización es una técnica de preprocesamiento de datos que se usa para escalar las características para estar en el mismo intervalo, normalmente entre 0 y 1, de modo que un algoritmo de aprendizaje automático pueda procesarlos con mayor precisión. Por ejemplo, los rangos de edad e ingresos varían significativamente, siendo la edad la que suele estar en el rango de 0 a 100, mientras que los ingresos suelen estar en el rango de cero a miles. Visite la página de transformaciones de para obtener una lista más detallada y una descripción de las transformaciones de normalización.
Normalización mínima máxima
Tome los siguientes datos de entrada y cárgelos en un IDataView
denominado data
:
HomeData[] homeDataList = new HomeData[]
{
new ()
{
NumberOfBedrooms = 2f,
Price = 200000f
},
new ()
{
NumberOfBedrooms = 1f,
Price = 100000f
}
};
La normalización se puede aplicar a columnas con valores numéricos únicos, así como vectores. Normalice los datos de la columna Price
mediante la normalización min-max con el método NormalizeMinMax
.
// Define min-max estimator
var minMaxEstimator = mlContext.Transforms.NormalizeMinMax("Price");
// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer minMaxTransformer = minMaxEstimator.Fit(data);
// Transform data
IDataView transformedData = minMaxTransformer.Transform(data);
Los valores de precio originales [200000,100000]
se convierten en [ 1, 0.5 ]
mediante la fórmula de normalización MinMax
que genera valores de salida en el intervalo de 0 a 1.
Discretización
binning convierte los valores continuos en una representación discreta de la entrada. Por ejemplo, supongamos que una de las características es la edad. En lugar de usar el valor de antigüedad real, la discretización crea intervalos para ese valor. 0-18 puede ser un rango, otro podría ser 19-35 y así sucesivamente.
Tome los siguientes datos de entrada y cárgelos en un IDataView
denominado data
:
HomeData[] homeDataList = new HomeData[]
{
new ()
{
NumberOfBedrooms=1f,
Price=100000f
},
new ()
{
NumberOfBedrooms=2f,
Price=300000f
},
new ()
{
NumberOfBedrooms=6f,
Price=600000f
}
};
Normalice los datos en rangos con el método NormalizeBinning
. El parámetro maximumBinCount
permite especificar el número de contenedores necesarios para clasificar los datos. En este ejemplo, los datos se colocarán en dos contenedores.
// Define binning estimator
var binningEstimator = mlContext.Transforms.NormalizeBinning("Price", maximumBinCount: 2);
// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
var binningTransformer = binningEstimator.Fit(data);
// Transform Data
IDataView transformedData = binningTransformer.Transform(data);
El resultado de la discretización crea límites de rangos de [0,200000,Infinity]
. Por lo tanto, los rangos resultantes son [0,1,1]
porque la primera observación está comprendida entre 0 y 200 000 y las demás son mayores que 200 000, pero menores que infinito.
Trabajar con datos categóricos
Uno de los tipos de datos más comunes es datos categóricos. Los datos de categorías tienen un número finito de categorías. Por ejemplo, los estados de EE. UU., o una lista de los tipos de animales encontrados en un conjunto de imágenes. Tanto si los datos categóricos son características o etiquetas, deben asignarse a un valor numérico para que se puedan usar para generar un modelo de aprendizaje automático. Hay varias maneras de trabajar con datos categóricos en ML.NET, en función del problema que esté solucionando.
Asignación de valores de clave
En ML.NET, una clave es un valor entero que representa una categoría. La asignación de valores de clave se usa con más frecuencia para asignar etiquetas de cadena en valores enteros únicos para el entrenamiento y, después, volver a sus valores de cadena cuando el modelo se utilice para realizar una predicción.
Las transformaciones utilizadas para realizar la asignación de valores de clave son MapValueToKey y MapKeyToValue.
MapValueToKey
agrega un diccionario de asignaciones en el modelo para que MapKeyToValue
pueda efectuar la transformación inversa al realizar una predicción.
Codificación frecuente
Una codificación activa toma un conjunto finito de valores y los asigna a enteros cuya representación binaria tiene un único valor de 1
en posiciones únicas de la cadena. Una codificación activa puede ser la mejor opción si no hay ninguna ordenación implícita de los datos categóricos. En la tabla siguiente se muestra un ejemplo con códigos postales como valores brutos.
Valor bruto | Un valor codificado en caliente |
---|---|
98052 | 00...01 |
98100 | 00...10 |
... | ... |
98109 | 10...00 |
La transformación para convertir los datos categóricos en números codificados de acceso frecuente es OneHotEncoding
.
Aplicación de algoritmo hash
El hash es otra manera de convertir datos categóricos en números. Una función hash asigna datos de un tamaño arbitrario (una cadena de texto por ejemplo) a un número con un intervalo fijo. La aplicación de algoritmo hash puede ser una forma rápida y eficaz de vectorizar las características. Un ejemplo notable de uso de hash en el aprendizaje automático es el filtrado de correo no deseado, donde, en lugar de mantener un diccionario de palabras conocidas, se aplica un hash a todas las palabras del correo electrónico y se agregan a un vector de características extenso. El uso de hashing de esta manera evita el problema de la elusión maliciosa del filtrado de spam mediante el uso de palabras que no están en el diccionario.
ML.NET proporciona transformación hash para realizar operaciones de aplicación de algoritmo hash en texto, fechas y datos numéricos. Al igual que la asignación de claves de valor, las salidas de la transformación hash son tipos de clave.
Trabajar con datos de texto
Al igual que los datos de categorías, los datos de texto deben transformarse en características numéricas antes de usarlos para crear un modelo de aprendizaje automático. Visite la página de transformaciones para obtener una lista más detallada y una descripción de las transformaciones de texto.
Uso de datos, como los datos siguientes que se han cargado en un IDataView
:
ReviewData[] reviews = new ReviewData[]
{
new ReviewData
{
Description="This is a good product",
Rating=4.7f
},
new ReviewData
{
Description="This is a bad product",
Rating=2.3f
}
};
ML.NET proporciona la transformación FeaturizeText
que toma el valor de cadena de un texto y crea un conjunto de características a partir del texto aplicando una serie de transformaciones individuales.
// Define text transform estimator
var textEstimator = mlContext.Transforms.Text.FeaturizeText("Description");
// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer textTransformer = textEstimator.Fit(data);
// Transform data
IDataView transformedData = textTransformer.Transform(data);
La transformación resultante convierte los valores de texto de la columna Description
en un vector numérico similar al resultado siguiente:
[ 0.2041241, 0.2041241, 0.2041241, 0.4082483, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0, 0, 0, 0, 0.4472136, 0.4472136, 0.4472136, 0.4472136, 0.4472136, 0 ]
Las transformaciones que componen FeaturizeText
también pueden aplicarse individualmente para conseguir un mayor control de la generación de características.
// Define text transform estimator
var textEstimator = mlContext.Transforms.Text.NormalizeText("Description")
.Append(mlContext.Transforms.Text.TokenizeIntoWords("Description"))
.Append(mlContext.Transforms.Text.RemoveDefaultStopWords("Description"))
.Append(mlContext.Transforms.Conversion.MapValueToKey("Description"))
.Append(mlContext.Transforms.Text.ProduceNgrams("Description"))
.Append(mlContext.Transforms.NormalizeLpNorm("Description"));
textEstimator
contiene un subconjunto de operaciones realizadas por el método FeaturizeText
. La ventaja de una canalización más compleja es el control y la visibilidad de las transformaciones aplicadas a los datos.
Con la primera entrada como ejemplo, la siguiente es una descripción detallada de los resultados generados por los pasos de transformación definidos por textEstimator
:
texto original: este es un buen producto
Transformación | Descripción | Resultado |
---|---|---|
1. NormalizeText | Convierte todas las letras en minúsculas de forma predeterminada. | este es un buen producto |
2. TokenizeWords | Divide la cadena en palabras individuales | ["este","es","un","buen","producto"] |
3. RemoveDefaultStopWords | Quita las palabras irrelevantes, como es y un. | ["producto","bueno"] |
4. MapValueToKey | Asigna los valores a claves (categorías) en función de los datos de entrada. | [1,2] |
5. ProduceNGrams | Transforma el texto en una secuencia de palabras consecutivas | [1,1,1,0,0] |
6. NormalizeLpNorm | Escala las entradas por su valor lp-norm | [ 0.577350529, 0.577350529, 0.577350529, 0, 0 ] |