Förbereda data för att skapa en modell

Lär dig hur du använder ML.NET för att förbereda data för ytterligare bearbetning eller för att skapa en modell.

Data är ofta orena och glesa. ML.NET maskininlärningsalgoritmer förväntar sig att indata eller funktioner ska finnas i en enda numerisk vektor. På samma sätt måste värdet för att förutsäga (etikett), särskilt när det är kategoriska data, kodas. Därför är ett av målen med dataförberedelser att få data till det format som förväntas av ML.NET algoritmer.

Dela upp data i tränings- och testuppsättningar

I följande avsnitt beskrivs vanliga problem när du tränar en modell som kallas överanpassning och underanpassning. Genom att dela upp dina data och validera dina modeller med hjälp av en uthållen uppsättning kan du identifiera och åtgärda dessa problem.

Överanpassning och underanpassning

Överanpassning och underanpassning är de två vanligaste problemen du stöter på när du tränar en modell. Underanpassning innebär att den valda tränaren inte är tillräckligt kapabel för att passa träningsdatauppsättningen och resulterar vanligtvis i en hög förlust under träning och låg poäng/mått på testdatauppsättningen. För att lösa detta måste du antingen välja en kraftfullare modell eller utföra mer funktionsframställning. Överanpassning är motsatsen, vilket händer när modellen lär sig träningsdata för bra. Detta resulterar vanligtvis i mått för låg förlust under träning men hög förlust på testdatauppsättningen.

En bra analogi för dessa begrepp är att studera för en examen. Anta att du kände till frågorna och svaren i förväg. Efter studierna tar du testet och får en perfekt poäng. Goda nyheter! Men när du får provet igen med frågorna omorganiserade och med lite olika formuleringar får du en lägre poäng. Det tyder på att du memorerade svaren och faktiskt inte lärde dig de begrepp som du testades på. Det här är ett exempel på överanpassning. Underanpassning är motsatsen där studiematerialet du fick inte korrekt representerar vad du utvärderas för provet. Därför tillgriper du att gissa svaren eftersom du inte har tillräckligt med kunskap för att svara korrekt.

Dela upp data

Ta följande indata och läs in dem i ett IDataView med namnet 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
    }
};

Om du vill dela upp data i tränings-/testuppsättningar använder du TrainTestSplit(IDataView, Double, String, Nullable<Int32>) metoden.

// Apply filter
TrainTestData dataSplit = mlContext.Data.TrainTestSplit(data, testFraction: 0.2);

Parametern testFraction används för att ta 0,2 eller 20 % av datamängden för testning. Återstående 80 % används för träning.

Resultatet är DataOperationsCatalog.TrainTestData med två IDataViews som du kan komma åt via TrainSet och TestSet.

Filtrera data

Ibland är inte alla data i en datamängd relevanta för analys. En metod för att ta bort irrelevanta data är filtrering. Innehåller DataOperationsCatalog en uppsättning filteråtgärder som tar in en IDataView som innehåller alla data och returnerar en IDataView som endast innehåller de datapunkter som är intressanta. Det är viktigt att observera att eftersom filteråtgärder inte är en IEstimator eller liknande i TransformsCatalog, kan de inte inkluderas som en del av en EstimatorChain pipeline för dataförberedelse eller TransformerChain dataförberedelseITransformer.

Ta följande indata och läs in dem i ett IDataView med namnet data:

HomeData[] homeDataList = new HomeData[]
{
    new ()
    {
        NumberOfBedrooms=1f,
        Price=100000f
    },
    new ()
    {
        NumberOfBedrooms=2f,
        Price=300000f
    },
    new ()
    {
        NumberOfBedrooms=6f,
        Price=600000f
    }
};

Om du vill filtrera data baserat på värdet för en kolumn använder du FilterRowsByColumn metoden .

// Apply filter
IDataView filteredData = mlContext.Data.FilterRowsByColumn(data, "Price", lowerBound: 200000, upperBound: 1000000);

Exemplet ovan tar rader i datamängden med ett pris mellan 200000 och 1000000. Resultatet av att tillämpa det här filtret returnerar endast de två sista raderna i data och exkluderar den första raden eftersom priset är 100000 och inte mellan det angivna intervallet.

Ersätt saknade värden

Saknade värden är en vanlig förekomst i datauppsättningar. En metod för att hantera saknade värden är att ersätta dem med standardvärdet för den angivna typen om något eller något annat meningsfullt värde, till exempel medelvärdet i data.

Ta följande indata och läs in dem i ett IDataView med namnet data:

HomeData[] homeDataList = new HomeData[]
{
    new ()
    {
        NumberOfBedrooms=1f,
        Price=100000f
    },
    new ()
    {
        NumberOfBedrooms=2f,
        Price=300000f
    },
    new ()
    {
        NumberOfBedrooms=6f,
        Price=float.NaN
    }
};

Observera att det sista elementet i listan saknar värde för Price. Om du vill ersätta de saknade värdena i Price kolumnen använder du ReplaceMissingValues metoden för att fylla i det saknade värdet.

Viktigt!

ReplaceMissingValue fungerar bara med numeriska data.

// 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 stöder olika ersättningslägen. Exemplet ovan använder Mean ersättningsläget, som fyller i det saknade värdet med kolumnens genomsnittliga värde. Ersättningsresultatet Price fyller i egenskapen för det sista elementet i våra data med 200 000 eftersom det är genomsnittet på 100 000 och 300 000.

Använda normaliserare

Normalisering är en dataförbearbetningsteknik som används för att skala funktioner så att de ligger inom samma intervall, vanligtvis mellan 0 och 1, så att de kan bearbetas mer korrekt av en maskininlärningsalgoritm. Till exempel varierar intervallen för ålder och inkomst avsevärt med åldern i allmänhet i intervallet 0-100 och inkomsten är vanligtvis i intervallet noll till tusentals. På sidan transformeringar finns en mer detaljerad lista och beskrivning av normaliseringstransformeringar.

Min-Max-normalisering

Ta följande indata och läs in dem i ett IDataView med namnet data:

HomeData[] homeDataList = new HomeData[]
{
    new ()
    {
        NumberOfBedrooms = 2f,
        Price = 200000f
    },
    new ()
    {
        NumberOfBedrooms = 1f,
        Price = 100000f
    }
};

Normalisering kan tillämpas på kolumner med enkla numeriska värden samt vektorer. Normalisera data i Price kolumnen med min-max-normalisering med NormalizeMinMax metoden .

// 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);

De ursprungliga prisvärdena [200000,100000] konverteras till [ 1, 0.5 ] med hjälp av MinMax normaliseringsformeln som genererar utdatavärden i intervallet 0–1.

Binning

Binning konverterar kontinuerliga värden till en diskret representation av indata. Anta till exempel att en av dina funktioner är ålder. I stället för att använda det faktiska åldersvärdet skapar binning intervall för det värdet. 0-18 kan vara en fack, en annan kan vara 19-35 och så vidare.

Ta följande indata och läs in dem i ett IDataView med namnet data:

HomeData[] homeDataList = new HomeData[]
{
    new ()
    {
        NumberOfBedrooms=1f,
        Price=100000f
    },
    new ()
    {
        NumberOfBedrooms=2f,
        Price=300000f
    },
    new ()
    {
        NumberOfBedrooms=6f,
        Price=600000f
    }
};

Normalisera data till lagerplatser med hjälp av NormalizeBinning metoden . Med maximumBinCount parametern kan du ange det antal lagerplatser som behövs för att klassificera dina data. I det här exemplet placeras data i två lagerplatser.

// 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);

Resultatet av binning skapar bin-gränser för [0,200000,Infinity]. Därför beror [0,1,1] de resulterande intervallen på att den första observationen är mellan 0 och 200000 och de andra är större än 200000 men mindre än oändligheten.

Arbeta med kategoriska data

En av de vanligaste typerna av data är kategoriska data. Kategoridata har ett begränsat antal kategorier. Till exempel delstaterna i USA eller en lista över de typer av djur som finns i en uppsättning bilder. Oavsett om kategoridata är funktioner eller etiketter måste de mappas till ett numeriskt värde så att de kan användas för att generera en maskininlärningsmodell. Det finns ett antal sätt att arbeta med kategoriska data i ML.NET, beroende på vilket problem du löser.

Nyckelvärdesmappning

I ML.NET är en nyckel ett heltalsvärde som representerar en kategori. Nyckelvärdesmappning används oftast för att mappa strängetiketter till unika heltalsvärden för träning och sedan tillbaka till deras strängvärden när modellen används för att göra en förutsägelse.

De transformeringar som används för att utföra nyckelvärdesmappning är MapValueToKey och MapKeyToValue.

MapValueToKey lägger till en ordlista med mappningar i modellen, så att MapKeyToValue du kan utföra omvänd transformering när du gör en förutsägelse.

En frekvent kodning

En frekvent kodning tar en begränsad uppsättning värden och mappar dem till heltal vars binära representation har ett enda 1 värde i unika positioner i strängen. En frekvent kodning kan vara det bästa valet om det inte finns någon implicit ordning på kategoridata. I följande tabell visas ett exempel med postnummer som råvärden.

Rått värde Ett snabbkodat värde
98052 00...01
98100 00...10
... ...
98109 10...00

Transformering för att konvertera kategoriska data till en-frekvent kodade tal är OneHotEncoding.

Hashing

Hashing är ett annat sätt att konvertera kategoriska data till tal. En hash-funktion mappar data av godtycklig storlek (till exempel en textsträng) till ett tal med ett fast intervall. Hashning kan vara ett snabbt och utrymmeseffektivt sätt att vektorisera funktioner. Ett viktigt exempel på hashning i maskininlärning är skräppostfiltrering via e-post, där varje ord i e-postmeddelandet hashas och läggs till i en stor funktionsvektor i stället för att behålla en ordlista med kända ord. Genom att använda hashning på det här sättet undviker du problemet med filtrering av skadlig skräppost genom att använda ord som inte finns i ordlistan.

ML.NET tillhandahåller Hash-transformering för att utföra hashning på text, datum och numeriska data. Precis som värdenyckelmappning är utdata från hash-transformering viktiga typer.

Arbeta med textdata

Precis som kategoriska data måste textdata omvandlas till numeriska funktioner innan de används för att skapa en maskininlärningsmodell. Besök sidan transformeringar för en mer detaljerad lista och beskrivning av texttransformeringar.

Använda data som data nedan som har lästs in i en 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 tillhandahåller transformering FeaturizeText som tar en texts strängvärde och skapar en uppsättning funktioner från texten genom att tillämpa en serie enskilda transformeringar.

// 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);

Den resulterande transformeringen konverterar textvärdena i Description kolumnen till en numerisk vektor som ser ut ungefär som utdata nedan:

[ 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 ]

De transformeringar som utgör FeaturizeText kan också tillämpas individuellt för finare kornkontroll över funktionsgenerering.

// 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 innehåller en delmängd av åtgärder som utförs av FeaturizeText metoden. Fördelen med en mer komplex pipeline är kontroll och synlighet över de omvandlingar som tillämpas på data.

Med den första posten som exempel är följande en detaljerad beskrivning av resultaten som genereras av transformeringsstegen som definieras av textEstimator:

Originaltext: Det här är en bra produkt

Transformering beskrivning Resultat
1. NormalizeText Konverterar alla bokstäver till gemener som standard detta är en bra produkt
2. TokenizeWords Delar upp strängen i enskilda ord ["this","is","a","good","product"]
3. RemoveDefaultStopWords Tar bort stoppord som is och a. ["good","product"]
4. MapValueToKey Kartor värdena till nycklar (kategorier) baserat på indata [1,2]
5. ProduceNGrams Omvandlar text till sekvens med efterföljande ord [1,1,1,0,0]
6. NormalizeLpNorm Skala indata efter deras lp-norm [ 0.577350529, 0.577350529, 0.577350529, 0, 0 ]