Regression med Genetiska Algoritmer Projektarbete, Artificiell intelligens, 729G43 Jimmy Eriksson, jimer336 770529-5991 2014
Inledning Hur många kramar finns det i världen givet? Att kunna estimera givet ett antal olika variabler är något som många vill kunna, men som ofta innebär mer eller mindre chansningar. En svårighet är att verkligheten ofta innebär många olika variabler, och att de interagerar med varandra på oförutsedda sätt. I denna rapport utvärderas ett eget program i försök att hitta de modeller som bäst passar givna data med två eller flera linjära och- eller ickelinjära variabler. Programmet hämtar idéer från analytisk regression och genetiska algoritmer. Regression Inom statistik används regressionsanalys för att finna den modell som har det minsta felet givet de data som används. Modellerna kan sedan användas för att förutsäga resultat givet de variabler som används. Ett exempel är att observerade data kan finnas för hur väl någon presterar på något prov givet variabeln timmars träning. Modellen kan enklast beskrivas som en matematisk funktion med ett antal oberoende (förklarande) variabler som ger ett resultat på en beroende variabel. Formeln uttrycks principiellt som: Ŷ = α + βx En vanlig distinktion är att göra mellan modeller som är linjärar och icke-linjära. Skillnaden mellan dessa två är enkelt uttryckt hur modellen kan ritas ut är modellen linjär är det en rak linje som ritas ut i ett koordinatsystem, och är modellen icke-linjär har den en annan form. Linjär regression Den enklaste typen av regression kallas enkel linjär regression. Modellen använder sig endast av en oberoende variabel. Nedan ses exempel på detta. Ŷ = α + βx Ŷ = 5 + 2x
Ofta är enkel linjär regression alltför enkel för att förklara en beroende variabel bra genom endast en oberoende. En mer komplex modell använder två eller fler variabel eller så kallad multipel regression. Liksom enkel regression ger modellen en linjär funktion. Multipel regression uttrycks som: Ŷ = α + β 1 x 1 + β 2 x 2 + β n x n Ŷ = 1 + 2x 1 + 3x 2. Icke-linjär regression Långt från alla observerade data passar bra med linjära funktioner. Det är möjligt att en variabel har störst verkan vid ett viss värde. Nedan visas exempel på en icke-linjär modell såväl matematiskt uttryckt som grafiskt. Ŷ = α + f(x) Ŷ = 5-2x 2 Icke-linjära modeller kan vara mycket komplexa då det finns otaliga möjliga former en kurva kan ta, och därför svåra att skapa. Error, ε Det är mycket ovanligt med modeller utan någon typ av fel. Alltså modeller där alla oberoende variabler ger den beroende variabelns observerade värde. Detta fel i modellen gör att vi kan uttrycka formeln som:
Ŷ = α + βx + ε Felet mellan en modell och observerade data illusteras i bilden nedan där punkterna är observerade data och modellen är linjen. Felet ger möjlighet att värdera hur bra modellen är mot de observerade datan som använts. Att påpeka är att denna metod inte tar hänsyn till variationer i de observerade datan. Det vill säga att outliers och liknande problem måste tas hänsyn till innan en analys genomförs. Skillnaden i hur bra olika modeller passar på observerade data illustreras nedan. Där visas observerade data som punkter och modellerna som linjer. Målet är, som tidigare nämnts, att hitta en modell med minsta möjliga fel som kan beskriva de observerade datan. Genom att välja den modell som har minst fel kan vi vara mer säkra på att estimerade värden stämmer. Ett vanligt sätt att beräkna fel är att använda sig av minsta kvadratfel-principen. Principen innebär att summera kvadraten av felet som ett y-värde faktiskt har subtraherat med det y- värde som modellen ger. Formelns fel = Σ (Y n - modellens Y) 2. Ett exempel följer nedan.
Observerade Data Ŷ = 5 + 4x y x Ŷ ε ε 2 7 1 5 + 4 * 1 = 9 7-9 = -2 (-2) 2 = 4 10 2 13-3 9 13 3 17-4 16 16 4 21-5 25 19 5 25-6 36 Fel = 4+9+16+25+36 = 90 Genetiska algoritmer Genetiska algoritmer bygger på evolutionsteorin där goda anlag (DNA) i en omgivning förs vidare till nya generationer. De bästa individerna paras och får avkommor med delar av föräldrarnas DNA. Detta tillsammans med mutation av föräldrarnas dna används för att försöka finna den bästa lösningen till ett problem. Cross-over innebär att ta delar av föräldrarnas DNA och sätta ihop dessa till nya individer som testas i en ny generation. Det finns olika sätt att bestämma var DNA-sekvensen ska brytas och sammanföras med annan DNA-sekvens. En vanlig lösning är att ta halva DNAsekvensen från var och en av föräldrarna. Detta visas i exemplet nedan (tabell 1). Mutation innebär att ta en eller flera delar av föräldern och förändra på något sätt. Detta ger en ökad variation i generationens population. En enkel mutation av föräldrarna X och Y visas i tabell 1. Förälder X 0 0 0 0 0 0 0 0 Förälder Y 1 1 1 1 1 1 1 1 Cross-over Barn XY 0 0 0 0 1 1 1 1 Cross-over Barn YX 1 1 1 1 0 0 0 0 Mutation X 0 0 0 0 1 0 0 0 Mutation Y 1 1 1 1 1 1 1 0 Tabell 1: Cross-over & Mutation Eftersom det endast är de bästa anlagen för omgivningen som är intressanta att föra vidare krävs någon typ av värdering av DNA-sekvenserna. En viktig poäng med genetiska algoritmer är att de inte garanterar en optimal lösning, men att de kan användas för att få fram relativt goda lösningar snabbt. Metod Ett program skrevs genom idéer från regression och genetiska algoritmer. Syftet med programmet var att utvärdera genetiska algoritmer för att göra regressionsanalys. Programvara
Python 2.7 användes för att skriva koden för att få fram den modell som bäst passar givna data. Data hämtas in som en given csv fil som innehåller y-värdet i första kolumnen och sedan de givna oberoende variablerna i följande kolumner. (Se appendix.) Indata Programmet tar in fyra argument. Det första är namnet på datafilen. De följande tre är frivilliga. Det första av dessa argument är antalet generationer som programmet genomför, och har ett standardvärde på 2000. Det andra är att förutom addition och subtraktion även tillåta multiplikation och division där standardvärdet är False. Det sista argumentet anger om programmet ska kunna använda sig av decimaltal eller inte, och standard är endast heltal. Regression( filnamn.csv, antal generationer, alla operatorer, decimaltal) Regression( testfil.csv, 1000, True, False) Implementerade funktioner Functions Klassen Functions skapades för att hålla information om varje oberoende variabel. Klassen har attribut såsom betavärde, operator och funktion. Dessa tre attribut kan ändras, vilket möjliggör mutationer. Exempelvis kan en mutation innebära byte av operator. Beroende på argument vid start så används vissa operatorer samt möjliggör eller begränsar decimaltalsberäkningar. Ett begränsat antal funktioner lades in för att kunna utvärdera resultatet av programmet. Bland dessa var: βx βx 2 β/x) βe x Regression En annan klass programmet använder sig av är Regression. Den tar en fil som indata och ger en modell som utdata. Klassen hanterar instanser av Functions och beräknar modellen enligt principen: Ŷ = α + f 1 (x 1 ) + f 2 (x 2 ) + f n (x n ) Klassen väljer ut de två bästa individerna i varje generation enligt minsta kvadratfel-principen och muterar dessa en gång vardera i operator, betavärde eller funktionstyp. En crossover genomförs även av de två bästa individerna genom att klyva modellens DNA-sekvens på
mitten och sätta ihop dessa till nya individer. Klassen skriver även ut den hittills bästa funna modellen. Implementerade begränsningar Ett antal begränsningar lades in i programmet. Dessa var att endast använda operatorerna addition och subtraktion. Ytterligare begränsning är att programmet endast använder heltal. Båda begränsningarna kan tas bort genom argument när programmet körs. Att använda begränsningarna kan ge sämre modeller men ge approximativ information. En ytterligare begränsning är att den csv-fil som används måste vara formaterad korrekt. Det vill säga att den har den beroende variabeln i första kolumnen, och resterade oberoende variabler följer. Inga. Ytterligare krävs att decimaltal använder punkt, vilket annars ger upphov till felmeddelande, Alfa- och beta-värden är för närvarande begränsade till att vara mellan -2 och 2. De kan ökas genom multiplikation då mutation genomförs och minskas med division. Om detta är ett bra sätt att arbeta är mycket säkert. En utvärdering av hur detta bör se ut bör göras. CSV-filer Fyra olika CSV-filer skapades för att testa programmet. Två av dem hade kända modeller och två hade obestämda. Alla testades med programmet. Resultat Test 1 Indata: Testfil 1 Utdata: Current Best Model: 0.0+2.0x+1.0x**2 Mean Squared Error: 0.0 R Square = 1.0 Test 3 Indata: Testfil 3 Utdata: Current Best Model: 0.34941827257+0.902609561094x Mean Squared Error: 1.08261533942 R Square = 0.861380878436 Test 2 Indata; Testfil 2 Utdata: Current Best Model: 0.0+1.0x-1.0x**2+1.0e**x Mean Squared Error: 2.48701993594e-18 R Square = 1.0 Test 4 Indata: Testfil 4 Utdata: Current Best Model: 4.0+1.0x+1.0x-3.0x+2.0x Mean Squared Error: 3.9 R Square = 0.527272727273 Test 1 och 2 hittade de förutbestämda modellerna. Test 3 använde data inspirerade av funktionen Y = 1.0x. En manuell beräkning av data från test 3 visade att den bästa modellen
som kan fås är 0.333+0.903x, vilket kan jämföras med programmets 0.34941827257+0.902609561094x. Test 4 grundade sig på helt slumpartade data med fyra oberoende variabler. Diskussion De fyra körningarna gav gott resultat och visar på att genetiska algoritmer kan lösa regressionsanalys. Problem och möjliga förbättringar Under flera testkörningar visade det sig att e x misstogs för x 2. Ett alternativ vore att endast en exponentiell funktion finns att tillgå. Färre funktionstyper kan ge snabbare resultat men ge ett större fel. Detta är en avvägning som får utvärderas. Ytterligare typer av funktioner bör implementeras för att hitta andra typer av kurvor. Exempelvis naturlig logaritm. Att ha i åtanke är att ju fler funktioner som finns att tillgå desto fler generationer kan krävas. En möjlig förbättring är att dela upp programmet i två delar: ett för att först hitta de funktioner som bäst passar in på datan, och sedan använda dem för att bestämma funktionernas alpha- och beta-värden. Möjligen ger detta bättre resultat. Ett problem som upptäcktes i programmet var att när csv-filen lästes in och innehöll decimaltal så gavs felmeddelanden. Det är därför viktigt att filen delar av decimaler från heltal med punkt. Dessutom är.csv-filer idag inte ett vanligt format. Att ge möjligheten att arbeta med andra filtyper såsom.xls och/eller.spss vore underlättande. Ytterligare en möjlig förbättring av programmet är att det inte endast tar hänsyn till en fil utan ger användaren möjlighet att välja fler filer och oberoende variabler. Att ge möjligheten att hämta och namnge variabler från olika filer. Detta för att ge mer flexibilitet och säkerhet åt användaren. Under programmets utveckling märktes att en funktion i python gav felaktiga resultat. Funktionen är eval(), vilken tar en sträng som argument och beräknar den. Att använda sig av denna funktion bör undersökas vid komplexa beräkningar så inga fel dyker upp. Särskilt kan detta tänkas hända vid operationer som involverar division och multiplikation. Ett problem som förblivit olöst är de fall där x = 0 och ett tal försöker divideras med x. Detta ger i normalfall ett resultat av inf, och hanteras inte av programmet. Ytterligare en funktion som skulle kunna finnas vore en som visar den differens som finns mellan Ŷ och Y. Denna funktion skulle visa en okänd variabel och hur felen varierar med en modell.
APPENDIX Datafil 1: Y = 2*X1 + (X2)2 102 1 10 85 2 9 70 3 8 57 4 7 46 5 6 37 6 5 30 7 4 25 8 3 22 9 2 21 10 1 Datafil 2: Y = 0.0+1.0x-1.0x 2 +1.0e x -29.2817 4 6 1-7.28172 6 4 1-10.6109 7 5 2-8.91446 7 6 3-50.2817-4 7 1-52.6109 4 8 2-57.9145 3 9 3-57.2817 4 8 1 Datafil 3: Y = 1.0x + error 2 1 2 2 2 3 3 4 6 5 7 6 6 7 6 8 10 9 9 10
Datafil 4: Y = okänd 1 4 7 8 7 2 5 7 8 6 3 6 6 8 5 4 7 5 7 5 5 6 4 6 4 6 5 3 5 3 7 4 4 4 4 8 3 5 5 5 9 4 6 6 6 10 5 6 7 7