Zephyrnet-logotyp

Förstå SVM-hyperparametrar

Datum:

Beskrivning

Den här guiden är den andra delen av tre guider om Support Vector Machines (SVM). I den här guiden kommer vi att fortsätta arbeta med användningsfallet för förfalskade sedlar, förstå vilka SVM-parametrar som redan ställs in av Scikit-learn, vad är C- och Gamma-hyperparametrar och hur man ställer in dem med hjälp av korsvalidering och rutnätssökning.

I den kompletta serien av SVM-guider kommer du, förutom SVM-hyperparametrar, också lära dig om enkla SVM, ett koncept som kallas kärntrick, och utforska andra typer av SVM.

Om du vill läsa alla guiderna, ta en titt på den första guiden eller se vilka som intresserar dig mest, nedan är tabellen över ämnen som tas upp i varje guide:

  1. Implementering av SVM och Kernel SVM med Pythons Scikit-Learn
  • Användningsfall: glöm sedlar
  • Bakgrund till SVM
  • Enkel (linjär) SVM-modell
    • Om datamängden
    • Importera datamängden
    • Utforska datasättet
  • Implementering av SVM med Scikit-Learn
    • Dela upp data i tåg/testuppsättningar
    • Träna modellen
    • Förutsäga
    • Utvärdering av modellen
    • Tolka resultat

2. Förstå SVM-hyperparametrar

  • Hyperparametern C
  • Gamma-hyperparametern

3. Implementera andra SVM-smaker med Pythons Scikit-Learn (kommer snart!)

  • SVMs allmänna idé (en sammanfattning)
  • Kärna (trick) SVM
  • Implementering av icke-linjär kärna SVM med Scikit-Learn
  • Importerar bibliotek
    • Importera datauppsättningen
    • Dela upp data i funktioner (X) och mål (y)
    • Dela upp data i tåg/testuppsättningar
    • Att träna algoritmen
  • Polynomkärna
    • Förutsäga
    • Utvärdera algoritmen
  • Gaussisk kärna
    • Förutsägelse och utvärdering
  • Sigmoidkärna
    • Förutsägelse och utvärdering
  • Jämförelse av icke-linjära kärnprestanda

Låt oss lära oss hur man implementerar korsvalidering och utför en hyperparameterjustering.

SVM hyperparametrar

För att se alla modellparametrar som redan har ställts in av Scikit-learn och dess standardvärden kan vi använda get_params() metod:

svc.get_params()

Denna metod visar:

{'C': 1.0, 'break_ties': False, 'cache_size': 200, 'class_weight': None, 'coef0': 0.0, 'decision_function_shape': 'ovr', 'degree': 3, 'gamma': 'scale', 'kernel': 'linear', 'max_iter': -1, 'probability': False, 'random_state': None, 'shrinking': True, 'tol': 0.001, 'verbose': False}

Lägg märke till att det finns totalt 15 hyperparametrar som redan ställs in, detta händer eftersom SVM-algoritmen har många variationer. Vi har använt den linjära kärnan för att få en linjär funktion, men det finns även kärnor som beskriver andra typer av funktioner och dessa kärnor parametriseras på olika sätt.

Dessa variationer råkar göra modellen mer flexibel och lämplig för att hitta en separation mellan olika former av data. Om vi ​​kan dra en linje för att separera våra klasser, då a linjär kärna kommer att vara ett bra alternativ, om vi behöver en kurva, då en polynom kärnan kan vara det bästa valet, om vår data har cirkulära former, då en Radiell basfunktion or RBF kärnan kommer att passa data bättre, om det finns värden över och under en tröskel, en sigmoid kärnan kan separera klasserna bättre. Av vad vi har utforskat i våra data verkar det som att antingen en RBF eller en polynomkärna skulle vara mer lämplig än en linjär kärna.

Nu när vi har en idé om att det finns 4 typer av olika kärnfunktioner kan vi gå tillbaka till parametrarna. När SVM-algoritmen försöker hitta en separation mellan klasser har vi redan förstått att den ritar en klassificering marginal mellan stödvektorerna och separationslinjen (eller kurvan).

Denna marginal är på sätt och vis som en buffert mellan separationslinjen och punkterna. Marginalstorleken kan variera när marginalen är mindre, det finns mindre utrymme för punkter som faller utanför marginalen, vilket gör separationen mellan klasser tydligare, så fler prover rätt klassificerad, omvänt, när marginalen är större, är separationen mellan klasser mindre tydlig, och fler sampel kan vara felklassificerad. Med andra ord innebär en mindre marginal mer korrekt klassificerade prover, och även ett mer styv klassificerare, medan en större marginal, betecknar fler felklassificerade sampel, men en mer flexibel klassificerare.

När dessa marginaler väljs är parametern som bestämmer dem C parameter.

Hyperparametern C

Smakämnen C parametern är omvänt proportionell mot marginalstorleken, detta betyder att större värdet av C, den mindre marginalen och omvänt mindre värdet av C, den större marginalen. De C parametern kan användas tillsammans med vilken kärna som helst, den talar om för algoritmen hur mycket man ska undvika att felklassificera varje träningsprov, på grund av det är den också känd som legaliserings. Vår linjära kärna SVM har använt en C på 1.0, vilket är en Large värde och ger en mindre marginal.

Vi kan experimentera med en mindre värdet på 'C' och förstå i praktiken vad som händer med en större marginal. För att göra det kommer vi att skapa en ny klassificerare, svc_c, och ändra endast värdet på C till 0.0001. Låt oss också upprepa fit och predict steg:

svc_c = SVC(kernel='linear', C=0.0001)
svc_c.fit(X_train, y_train)
y_pred_c = svc_c.predict(X_test)

Nu kan vi titta på resultaten för testdata:

print(classification_report(y_test, y_pred_c)) cm_c = confusion_matrix(y_test, y_pred_c)
sns.heatmap(cm_c, annot=True, fmt='d').set_title('Confusion matrix of linear SVM with C=0.0001')

Denna utgångar:

 precision recall f1-score support 0 0.82 0.96 0.88 148 1 0.94 0.76 0.84 127 accuracy 0.87 275 macro avg 0.88 0.86 0.86 275
weighted avg 0.88 0.87 0.86 275

Genom att använda en mindre C och genom att få en större marginal har klassificeraren blivit mer flexibel och med fler klassificeringsmisstag. I klassificeringsrapporten kan vi se att f1-score, tidigare 0.99 för båda klasserna, har sänkts till 0.88 för klass 0 och till 0.84 för klass 1. I förvirringsmatrisen gick modellen från 2 till 6 falskt positiva och från 2 till 31 falskt negativa.

Vi kan också upprepa predict steg och titta på resultaten för att kontrollera om det fortfarande finns en överanpassning när du använder tågdata:

y_pred_ct = svc_c.predict(X_train) cm_ct = confusion_matrix(y_train, y_pred_ct)
sns.heatmap(cm_ct, annot=True, fmt='d').set_title('Confusion matrix of linear SVM with C=0.0001 and train data') print(classification_report(y_train, y_pred_ct))

Detta resulterar i:

 precision recall f1-score support 0 0.88 0.96 0.92 614 1 0.94 0.84 0.88 483 accuracy 0.90 1097 macro avg 0.91 0.90 0.90 1097
weighted avg 0.91 0.90 0.90 1097

Genom att titta på resultaten med en mindre C och tågdata kan vi se att det var en förbättring i överanpassningen, men när de flesta mätvärden fortfarande är högre för tågdata verkar det som om överanpassningen inte har lösts. Så det är bara att ändra C parametern var inte tillräckligt för att göra modellen mer flexibel och förbättra dess generalisering.

Anmärkningar: Försöker hitta balans mellan att en funktion kommer för långt från data, är för fixerad eller har hög partiskhet eller så är det tvärtom, en funktion som passar till data, är för flexibel eller har hög varians brukar kallas för bias varians avvägning. Att hitta den balansen är inte trivialt, men när den uppnås finns det ingen underanpassning eller överanpassning av modellen till data. Som ett sätt att minska variansen och förhindra överanpassning kan uppgifterna jämnt krympas för att göras mer regelbundna och förenkla när man skaffar en funktion som beskriver den. Det är vad parametern C gör när det används i SVM, av den anledningen kallas det också L2-reglering or Åsregression.

Fram till denna punkt har vi förstått om marginalerna i SVM och hur de påverkar det övergripande resultatet av algoritmen, men hur är det med linjen (eller kurvan) som skiljer klasserna åt? Denna linje är beslutsgräns. Så vi vet redan att marginalerna har en inverkan på beslutsgränsens flexibilitet mot misstag, vi kan nu ta en titt på en annan parameter som också påverkar beslutsgränsen.

Kolla in vår praktiska, praktiska guide för att lära dig Git, med bästa praxis, branschaccepterade standarder och medföljande fuskblad. Sluta googla Git-kommandon och faktiskt lära Det!

Anmärkningar: Beslutsgränsen kan också kallas en hyperplan. Ett hyperplan är ett geometriskt koncept för att hänvisa till antalet dimensioner av ett utrymme minus en (dims-1). Om rymden är 2-dimensionell, till exempel ett plan med x- och y-koordinater, är de 1-dimensionella linjerna (eller kurvorna) hyperplanen. I maskininlärningssammanhang, eftersom antalet kolumner som används i modellen är dess plandimensioner, när vi arbetar med 4 kolumner och en SVM-klassificerare, hittar vi ett 3-dimensionellt hyperplan som separerar mellan klasser.

Gamma-hyperparametern

Oändliga beslutsgränser kan väljas, några av dessa gränser kommer att skilja klasserna åt och andra inte. När man väljer en effektiv beslutsgräns ska de första 10 närmaste punkterna i varje klass beaktas? Eller bör fler punkter övervägas, inklusive de punkter som ligger långt borta? I SVM definieras valet av intervall av en annan hyperparameter, gamma.

Tycka om C, gamma är något omvänt proportionell mot dess avstånd. De högre dess värde, den närmast är de punkter som beaktas för beslutsgränsen, och de lägst d gamma, den längre poäng beaktas också vid val av beslutsgräns.

En annan effekt av gamma är att ju högre dess värde är, desto mer kommer omfattningen av beslutsgränsen närmare punkterna runt den, vilket gör den mer taggig och benägen att överanpassa – och ju lägst dess värde är, desto jämnare och regelbunden blir beslutsgränsen. ytan blir också mindre benägen att överanpassas. Detta är sant för alla hyperplan, men kan lättare observeras när data separeras i högre dimensioner. I vissa dokument, gamma kan också kallas sigma.

När det gäller vår modell är standardvärdet på gamma var scale. Som det kan ses i Scikit-lär dig SVC-dokumentation, betyder det att dess värde är:

$$
gamma = (1/ text{n_features} * X.var())
$$

or

$$
gamma = (1/ text{number_of_features} * text{features_variance})
$$

I vårt fall måste vi beräkna variansen av X_train, multiplicera det med 4 och dividera resultatet med 1. Vi kan göra detta med följande kod:

number_of_features = X_train.shape[1] features_variance = X_train.values.var()
gamma = 1/(number_of_features * features_variance)
print('gamma:', gamma)

Denna utgångar:

gamma: 0.013924748072859962

Det finns också ett annat sätt att se på värdet av gamma, genom att komma åt klassificerarens objekt gamma parameter med ._gamma:

svc._gamma 

Vi kan se att gamma användes i vår klassificerare var låg, så den räknade också med längre bort poäng.

Anmärkningar: Som vi har sett, C och gamma är viktiga för vissa definitioner av modellen. En annan hyperparameter, random_state, används ofta i Scikit Learn för att garantera datablandning eller ett slumpmässigt frö för modeller, så vi har alltid samma resultat, men detta är lite annorlunda för SVM:s. Särskilt random_state har bara konsekvenser om en annan hyperparameter, probability, är satt till sant. Detta beror på att det kommer att blanda data för att erhålla sannolikhetsuppskattningar. Om vi ​​inte vill ha sannolikhetsuppskattningar för våra klasser och sannolikheten är inställd på falsk, kommer SVM:s random_state parametern har inga konsekvenser för modellresultaten.

Det finns ingen regel för hur man väljer värden för hyperparametrar, såsom C och gamma – det beror på hur länge och vilka resurser som finns tillgängliga för att experimentera med olika hyperparametervärden, vilka transformationer som kan göras till datan och vilka resultat som förväntas . Det vanliga sättet att söka efter hyperparametervärdena är genom att kombinera vart och ett av de föreslagna värdena genom a rutnätssökning tillsammans med en procedur som tillämpar dessa hyperparametervärden och erhåller mätvärden för olika delar av den anropade datan korsvalidering. I Scikit-learn är detta redan implementerat som GridSearchCV (CV från korsvalidering) metod.

För att köra en rutnätssökning med korsvalidering måste vi importera GridSearchCV, definiera en ordbok med värdena för hyperparametrar som kommer att experimenteras med, till exempel typen av kernel, intervallet för COch för gamma, skapa en instans av SVC, definiera score eller mätvärde kommer att användas för att utvärdera (här kommer vi att välja att optimera för både precision och återkallelse, så vi kommer att använda f1-score), antalet uppdelningar som kommer att göras i data för att köra sökningen i cv – standard är 5, men det är en bra praxis att använda minst 10 – här kommer vi att använda 5 dataveck för att göra det tydligare när vi jämför resultat.

Smakämnen GridSearchCV har en fit metod som tar emot våra tågdata och ytterligare delar upp den i tåg- och testset för korsvalideringen. Vi kan ställa return_train_score till sant för att jämföra resultaten och garantera att det inte finns någon överansträngning.

Detta är koden för rutnätssökningen med korsvalidering:

from sklearn.model_selection import GridSearchCV parameters_dictionary = {'kernel':['linear', 'rbf'], 'C':[0.0001, 1, 10], 'gamma':[1, 10, 100]}
svc = SVC() grid_search = GridSearchCV(svc, parameters_dictionary, scoring = 'f1', return_train_score=True, cv = 5, verbose = 1) grid_search.fit(X_train, y_train)

Denna kod matar ut:

Fitting 5 folds for each of 18 candidates, totalling 90 fits
# and a clickable GridSeachCV object schema

Efter att ha gjort hyperparametersökningen kan vi använda best_estimator_, best_params_ och best_score_ egenskaper för att få bästa modell, parametervärden och högsta f1-poäng:

best_model = grid_search.best_estimator_
best_parameters = grid_search.best_params_
best_f1 = grid_search.best_score_ print('The best model was:', best_model)
print('The best parameter values were:', best_parameters)
print('The best f1-score was:', best_f1)

Detta resulterar i:

The best model was: SVC(C=1, gamma=1)
The best parameter values were: {'C': 1, 'gamma': 1, 'kernel': 'rbf'}
The best f1-score was: 0.9979166666666666

För att bekräfta vår första gissning från att titta på data, har den bästa modellen inte en linjär kärna, utan en olinjär, RBF.

Råd: när du undersöker vidare är det intressant att du inkluderar fler icke-linjära kärnor i rutnätssökningen.

Både C och gamma har värdet 1, och f1-score är mycket hög, 0.99. Eftersom värdet är högt, låt oss se om det fanns en överansträngning genom att kika på medelprovet och tågresultaten som vi har returnerat, inuti cv_results_ objekt:

gs_mean_test_scores = grid_search.cv_results_['mean_test_score']
gs_mean_train_scores = grid_search.cv_results_['mean_train_score'] print("The mean test f1-scores were:", gs_mean_test_scores)
print("The mean train f1-scores were:", gs_mean_train_scores)

Medelpoängen var:

The mean test f1-scores were: [0.78017291 0. 0.78017291 0. 0.78017291 0. 0.98865407 0.99791667 0.98865407 0.76553515 0.98865407 0.040291 0.98656 0.99791667 0.98656 0.79182565 0.98656 0.09443985] The mean train f1-scores were: [0.78443424 0. 0.78443424 0. 0.78443424 0. 0.98762683 1. 0.98762683 1. 0.98762683 1. 0.98942923 1. 0.98942923 1. 0.98942923 1. ]

Genom att titta på medelpoängen kan vi se att den högsta, 0.99791667, dyker upp två gånger, och i båda fallen var poängen i tågdata 1. Detta tyder på att överfiten kvarstår. Härifrån skulle det vara intressant att gå tillbaka till dataförberedelsen och förstå om det är vettigt att normalisera data, göra någon annan typ av datatransformation och även skapa nya funktioner med funktionsteknik.

Vi har precis sett en teknik för att hitta modellens hyperparametrar, och vi har redan nämnt något om linjär separerbarhet, stödvektorer, beslutsgräns, maximering av marginaler och kärntrick. SVM är en komplex algoritm, vanligtvis med många matematiska begrepp inblandade och små tweakbara delar som behöver justeras för att komma samman som en helhet.

Låt oss kombinera det vi har sett hittills, göra en sammanfattning av hur alla delar av SVM fungerar och sedan ta en titt på några av de andra kärnimplementeringarna tillsammans med deras resultat.

Slutsats

I den här artikeln förstod vi om standardparametrarna bakom Scikit-Learns SVM-implementering. Vi förstod vad C- och Gamma-parametrar är och hur förändringar av var och en av dem kan påverka SVM-modellen.

Vi lärde oss också om rutnätssökning för att leta efter de bästa C- och Gamma-värdena och för att använda korsvalidering för att bättre generalisera våra resultat och garantera att det inte finns någon form av dataläckage.

Att utföra en hyperparameterjustering med rutnätssökning och korsvalidering är en vanlig praxis inom datavetenskap, så jag rekommenderar starkt att du implementerar teknikerna, kör koden och ser kopplingarna mellan hyperparametervärdena och förändringarna i SVM-förutsägelser.

plats_img

Senaste intelligens

plats_img

Chatta med oss

Hallå där! Hur kan jag hjälpa dig?