Regressionsanalys är en gren inom statistik där målet är att skapa en funktion som bäst passar observerad data.
Om man har en mängd data som kan placeras i ett koordinatsystem kan en linje ritas ut som som bäst visar på spridningen av denna data. Med linjen kan man få ett skapligt statistiskt underlag för förutsägelser utifrån befintlig data.
I programmet som ska skapas används en metod som kallas minsta kvadratmetoden för att beräkna var linjen ska ritas ut.
För att beräkna avståndet från datapunkterna ritas vertikala linjer ut. Linjerna kallas residualer. Avståndet till linjen för alla punkter summeras och linjens riktning anpassas så att summan av avstånden blir så litet som möjligt .
För att ytterligare förbättra linjens anpassning till datapunkterna används minsta kvadratmetoden. Varje residuals längd kvadreras. Detta görs för att några datapunkter ligger över linjen och några punkter ligger under linjen. I programmet blir då några avstånd negativa och andra positiva. Om värdena kvadreras blir de alla positiva.
Nu ska ett program skapas där datapunkter ritas ut på canvasen när musen klickas på. En linje ska anpassas så att den bäst representerar alla de utritade datapunkterna.
Linjen som ska ritas ut är en rät linje i formen y = kx +m
Bli inte förvånade om ni på andra webbsidor ser andra skrivsätt för räta linjens ekvation. Det kan stå y = mx + b eller y = b0 + b1x. Skrivsätten varierar i olika länder och/eller i olika sammanhang. Kom bara ihåg att den variabel som multipliceras med x är den variabel som anger lutningen.
Formel för att räkna ut k
Σ betyder summa. i =1 och n som står under och över summatecknet är ett matematiskt sätt att skriva att det gäller summan av alla x och y
X med streck över betyder medelvärde av alla x, dvs summan av alla x-värden delat med antalet x-värden.
Y med streck över betyder medelvärde av alla y, dvs summan av alla y-värden delat på antal y-värden
Formel för att beräkna m
Först skapas en variabel med namnet data och värdet sätts till en tom array. Arrayen kommer senare att innehålla de datapunkter som ritas ut på canvasen när musen kickas på.
En variabel med namnet k får värdet 1 och en variabel med namnet m får värdet 0. Dessa variabler kommer att användas till den räta linje som ska ritas ut.
i funktionen setup() ritas en canvas ut med storleken 400 * 400 pixlar
let data = []; let k = 1; let m = 0; function setup() { createCanvas(400, 400); }
Efter setup() skapas en funktion som ska rita ut datapunkter på canvasen och spara punkternas x- och y-värden i arrayen data. Funktionen som används är en funktion som finns färdig i p5.js och den heter mousePressed(). Två variabler x och y skapas som ska innehålla värdet för musens x- och y-position när musen klickas på. En variabel med namnet point används för att skapa en vektor av dessa positioner. Med data.push() läggs varje point sen till i arrayen data.
function mousePressed(){ let x = mouseX;// let y = mouseY; let points = createVector(x,y); data.push(points); }
I draw() sätts bakgrunden till en grå färg. En for-loop loopar igenom alla index i arrayen data. För varje index sparas x- respektive y-värdena i variablerna x och y.
Observera att de här variablerna x och y inte är samma som de som skapades i funktionen mousePressed(). Variabler som skapas i en funktion är lokala variabler och gäller bara inom klammerparenteser som omsluter funktionen. En variabel som skapas utanför funktioner (som var k och var m högst upp i detta program) är en global variabel och gäller överallt i programmet.
För varje index ritas en vit punkt ut.
function draw() { background(70); for(let i = 0; i <data.length; i++){ let x = data[i].x; let y =data[i].y; fill(255); stroke(255); ellipse(x, y,8,8); }
Nu kan datapunkter ritas ut på canvasen. I koden finns en rad där det står //console.log(data). I den widget som används här finns ingen konsol men om man använder p5.js editor så kan man ta bort det två kommentarstrecken och titta närmare på innehållet i arrayen data när några punkter klickats ut på canvasen. Där står bland annat indexnummer samt punktens x och y koordinater.
Efter mousePressed() skapas en ny funktion vilken ska hantera alla beräkningar av den linjära regressionen
Funktion får namnet linearRegression.
En variabel med namnet xsum och en med namnet ysum skapas. Båda får det initiala värdet 0. Dessa variabler kommer att användas för att kunna beräkna medelvärden för alla x- och y- värden
För att summera alla datapunkternas x-och y-värden skapas en for-loop som loopar igenom arrayen data. För varje datapunkt adderas dess x- och y-värden till variablerna xsum och ysum.
Efter for-loopen skapas två variabler för medelvärdet av alla x- och y-värden. Variablerna får namnen xmean och ymean .
En variabel med namnet num och värdet 0 skapas. num står för numerator vilket är engelska för täljare
En variabel med namnet den och värdet 0 skapas. den står denominator vilket är engelska för nämnare
En for-loop skapas vilken loopar igenom alla index i arrayen data. Två nya variabler med namnen x och y används för att innehålla datapunktens x- och y-värden. För varje index i arrayen plockas värdena för x och y ut och summeras till täljare och nämnare enligt formel som definieradet des tidigare
variabeln num kommer nu att ha värdet för som står i täljaren och variablen den kommer att ha värdet för det som står i nämnaren
Sist i funktionen beräknas k och m enligt tidigare definierade formler
function linearRegression(){ let xsum = 0; let ysum = 0; for(let i = 0; i < data.length; i++){ xsum += data[i].x; ysum += data[i].y; } let xmean = xsum / data.length; let ymean = ysum / data.length; let num = 0;//täljare let den = 0;//nämnare for(let i = 0; i < data.length; i++){ let x = data[i].x; let y = data[i].y; num += (x-xmean) * (y-ymean) den += (x-xmean) *(x-xmean); } k = num/den; m = ymean - k *xmean; }
En funktion för att rita linjen skapas.med namnet drawLine(). Fyra variabler med namnen x1, y1, x2, y2 skapas. x1 får värdet 0 eftersom linjen ska börja där x har värdet 0. Linjen ska ritas över hela canvasen så x2 sätts till 400. y1 och y2 sätts till formeln för räta linjens ekvation. Därefter ritas en lila linje ut.
function drawLine(){ let x1 = 0; let y1 = k * x1 + m; let x2 = 400; let y2 = k * x2 + m; stroke(255,0,255); line(x1,y1,x2,y2); }
i funktionen draw() läggs en if-sats till efter for-loopen. Den säger att om det finns två punkter (eller fler) kör funktionerna linearRegression() och drawLine()
if(data.length > 1){ linearRegression(); drawLine(); }
Nu fungerar programmet. Det finns dock en sak som inte är helt bra med det här programmet. Canvasen har sin origo i övre vänstra hörnet och det är sällan så det är när datapunkter ritas ut i tabeller. Det vanliga är att origo är i nedre vänstra hörnet.
För att ändra koordinatsystemet på canvasen så kan vi använda funktionen map()
du kan läsa mer om funktionen map här
x-axeln ligger rätt och går från 0 till 400. y-axeln behöver ändras så att 0 blir 400 och 400 blir 0.
I funktionen mousePressed() byts
let y = mouseY; till
let y= map(mouseY, 0, height, height, 0);
I funktionen drawline() lägger vi till två rader efter att variablerna skapats
y1 = map(y1, 0, height, height, 0);
y2 = map(y2, 0, height, height, 0);
I functionen draw() byts
let y =data[i].y; till
let y = map(data[i].y, 0, height, height ,0);
När axlarna mappats om, kan du skriva siffror på canvasen som visar respektive axels värden?