Linjär regression

Regressionsanalys är en gren inom statistik där målet är att skapa en funktion som bäst passar observerad data.

 Linje i koordinatsystem som visar det linjära sambandet mellan datapunkter

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.

Rät linje med vertikala residualer

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

var data = [];
var k = 1;
var 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(){
  var x = mouseX;//
  var y = mouseY;
  var 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(var i = 0; i <data.length; i++){
  var x = data[i].x;
  var 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(){
  var xsum = 0;
  var ysum = 0;
  for(var i = 0; i < data.length; i++){
    xsum += data[i].x;
    ysum += data[i].y;
  }
  var xmean = xsum / data.length;
  var ymean = ysum / data.length;

  var num = 0;//täljare
  var den = 0;//nämnare
  for(var i = 0; i < data.length; i++){
    var x = data[i].x;
    var 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(){
  var x1 = 0;
  var y1 = k * x1 + m;
  var x2 = 400;
  var 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
var y = mouseY; till
var 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
var y =data[i].y; till
var 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?