Doriți să știți cum să preziceți viitorul cu o formulă simplă și câteva date?

Există mai multe modalități de a aborda problema încercării de a prezice viitorul. Dar vom analiza teoria cum am putea face acest lucru cu formula Y = a + b * X.

După ce vom acoperi teoria, vom crea un proiect JavaScript. Acest lucru ne va ajuta să vizualizăm mai ușor formula în acțiune folosind Chart.js pentru a reprezenta datele.

Care este metoda de regresie a celor mai mici pătrate și de ce să o utilizați?

Cel mai mic pătrat este o metodă de aplicare a regresiei liniare. Ne ajută să prezicem rezultatele pe baza unui set existent de date, precum și anomalii clare în datele noastre. Anomaliile sunt valori prea bune sau rele pentru a fi adevărate sau care reprezintă cazuri rare.

De exemplu, să presupunem că avem o listă cu câte subiecte viitorii ingineri pot rezolva aici la Routech dacă investesc 1, 2 sau 3 ore continuu. Apoi, putem prezice câte subiecte vor fi acoperite după 4 ore de studiu continuu chiar și fără ca aceste date să ne fie disponibile.

Această metodă este utilizată de o multitudine de profesioniști, de exemplu statistici, contabili, manageri și ingineri (ca în problemele de învățare automată).

Configurarea unui exemplu

Înainte de a intra în formulă și cod, să definim datele pe care le vom folosi.

Pentru a face acest lucru, să extindem exemplul menționat mai devreme.

Să presupunem că obiectivul nostru este să ne dăm seama câte subiecte sunt acoperite de un student pe oră de învățare.

Fiecare pereche (X, Y) va reprezenta un elev. Deoarece toți avem rate diferite de învățare, numărul de subiecte rezolvate poate fi mai mare sau mai mic pentru același timp investit.

Ore (X) Subiecte rezolvate (Y)
1 1.5
1.2 2
1.5 3
2 1.8
2.3 2.7
2.5 4.7
2.7 7.1
3 10
3.1 6
3.2 5
3.6 8.9

O puteți citi astfel: „Cineva a petrecut 1 oră și a rezolvat 2 subiecte” sau „Un elev după 3 ore a rezolvat 10 subiecte”.

Într-un grafic, aceste puncte arată astfel:

Metoda de regresie a celor mai mici patrate Cum
Fiecare punct este un student (X, Y) și cât a durat acel student specific pentru a finaliza un anumit număr de subiecte

Declinare de responsabilitate: Aceste date sunt fictive și au fost făcute prin apăsarea tastelor aleatorii. Habar n-am de valorile reale.

Formula

Y = a + bX

Formula, pentru cei care nu sunt familiarizați cu aceasta, pare probabil copleșitoare – cu atât mai mult având în vedere faptul că avem deja valorile pentru Da și X în exemplul nostru.

Acestea fiind spuse și acum că nu ne sperie formula, trebuie doar să ne dăm seama A și b valori.

Pentru a da un anumit context cu privire la ceea ce înseamnă:

  • A este interceptarea, cu alte cuvinte valoarea pe care o așteptăm, în medie, de la un student care practică o oră. O oră este cel mai mic timp pe care îl vom accepta în exemplul nostru de date.
  • b este panta sau coeficientul, cu alte cuvinte numărul de subiecte rezolvate într-o anumită oră (X). Pe măsură ce creștem în ore (X) a petrecut studiind, b crește tot mai mult.

Se calculează „b”

1611418030 719 Metoda de regresie a celor mai mici patrate Cum
Pare mai înfricoșător decât este

X și Da sunt pozițiile noastre din tabelul nostru anterior. Când au o (macron) deasupra lor, înseamnă că ar trebui să folosim media pe care o obținem prin însumarea tuturor și împărțirea la suma totală:

X -> 1 + 1,2 + 1,5 + 2 + 2,3 + 2,5 + 2,7 + 3 + 3,1 + 3,2 + 3,6 = 2.37

.Y -> 1,5 + 2 + 3 + 1,8 + 2,7 + 4,7 + 7,1 + 10 + 6 + 5 + 8,9 / 11 = 4,79

Acum că avem media, ne putem extinde tabelul pentru a include noile rezultate:

Ore (X) Subiecte rezolvate (Y) (X – ͞x) (y – ͞y) (X – ͞x) * (y – ͞y) (x – ͞x) ²
1 1.5 -1,37 -3,29 4.51 1,88
1.2 2 -1,17 -2,79 3.26 1,37
1.5 3 -0,87 -1,79 1,56 0,76
2 1.8 -0,37 -2,99 1.11 0,14
2.3 2.7 -0.07 -2.09 0,15 0,00
2.5 4.7 0,13 -0.09 -0.01 0,02
2.7 7.1 0,33 2.31 0,76 0,11
3 10 0,63 5.21 3.28 0,40
3.1 6 0,73 1.21 0,88 0,53
3.2 5 0,83 0,21 0,17 0,69
3.6 8.9 1.23 4.11 5.06 1,51

Simbolul ciudat sigma () ne spune să rezumăm totul:

∑ (x – ͞x) * (y – ͞y) -> 4,51 + 3,26 + 1,56 + 1,11 + 0,15 + -0,01 + 0,76 + 3,28 + 0,88 + 0,17 + 5,06 = 20,73

∑ (x – ͞x) ² -> 1,88 + 1,37 + 0,76 + 0,14 + 0,00 + 0,02 + 0,11 + 0,40 + 0,53 + 0,69 + 1,51 = 7.41

Și în cele din urmă o facem 20,73 / 7,41 și obținem b = 2,8

Notă: Când utilizați un calculator de intrare expresie, cum ar fi cel disponibil în Ubuntu, -2² returnează -4 în loc de 4. Pentru a evita această intrare (-2) ².

Calculul „a”

Tot ce a mai rămas este A, pentru care formula este ͞͞͞Y = a + b ͞x. Am obținut deja toate celelalte valori, așa că le putem înlocui și obținem:

  • 4,79 = A + 2,8 * 2,37
  • 4,79 = A + 6,64
  • A = -6,64 + 4,79
  • a = -1,85

Rezultatul

Formula noastră finală devine:

Y = -1,85 + 2,8 * X

Acum înlocuim X în formula noastră cu fiecare valoare pe care o avem:

Ore (X) -1,85 + 2,8 * X
1 0,95
1.2 1,51
1.5 2.35
2 3,75
2.3 4.59
2.5 5.15
2.7 5,71
3 6,55
3.1 6,83
3.2 7.11
3.6 8.23

Care este un grafic care arată așa:

1611418031 13 Metoda de regresie a celor mai mici patrate Cum
Acum avem o linie care reprezintă câte subiecte ne așteptăm să fie rezolvate pentru fiecare oră de studiu

Dacă vrem să prezicem câte subiecte ne așteptăm ca un student să rezolve cu 8 ore de studiu, îl înlocuim în formula noastră:

  • Y = -1,85 + 2,8 * 8
  • Y = 20,55

Într-un grafic putem vedea:

1611418031 419 Metoda de regresie a celor mai mici patrate Cum
Cu cât este mai departe în viitor, cea mai mică precizie pe care ar trebui să o așteptăm

Limitări

Țineți cont întotdeauna de limitările unei metode. Sperăm că acest lucru vă va ajuta să evitați rezultatele incorecte.

Și această metodă, ca oricare alta, are limitele sale. Iată câteva:

  • Nu ia în considerare complexitatea subiectelor rezolvate. Un subiect acoperit la începutul „Certificării de proiectare web receptivă” va dura cel mai probabil să învețe și să rezolve mai puțin decât să faci unul dintre proiectele finale. Deci, dacă datele pe care le avem provin din diferite puncte de plecare ale unui curs, predicțiile nu vor fi corecte
  • Este imposibil ca cineva să studieze 240 de ore continuu sau să rezolve mai multe subiecte decât cele disponibile. Indiferent, metoda ne permite să prezicem acele valori. În acel moment, metoda nu mai dă rezultate cu exactitate, deoarece este imposibil.

Exemplu de proiect JavaScript

Nu este necesar să faceți acest lucru manual. Ne putem crea proiectul în care introducem valorile X și Y, desenează un grafic cu acele puncte și aplică formula de regresie liniară.

Dosarul proiectului va avea următorul conținut:

src/
  |-public // folder with the content that we will feed to the browser
    |-index.html
    |-style.css
    |-least-squares.js
  package.json
  server.js // our Node.js server

Și pachet.json:

{
  "name": "least-squares-regression",
  "version": "1.0.0",
  "description": "Visualize linear least squares",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "server-debug": "nodemon --inspect server.js"
  },
  "author": "daspinola",
  "license": "MIT",
  "devDependencies": {
    "nodemon": "2.0.4"
  },
  "dependencies": {
    "express": "4.17.1"
  }
}

Odată ce avem package.json și alergăm instalare npm vom avea Express și nodemon disponibile. Le puteți schimba pentru alții după cum preferați, dar le folosesc din comoditate.

În server.js:

const express = require('express')
const path = require('path')

const app = express()

app.use(express.static(path.join(__dirname, 'public')))

app.get('/', function(req, res) {
  res.sendFile(path.join(__dirname, 'public/index.html'))
})

app.listen(5000, function () {
  console.log(`Listening on port ${5000}!`)
})

Acest mic server este creat astfel încât să putem accesa pagina noastră atunci când scriem în browser localhost: 5000. Înainte de al rula, să creăm fișierele rămase:

public / index.html

<html>
  <head>
    <title>Least Squares Regression</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/Chart.min.js"></script>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div class="container">
      <div class="left-half">
        <div>
          <input type="number" class="input-x" placeholder="X">
          <input type="number" class="input-y" placeholder="Y">

          <button class="btn-update-graph">Add</button> 
        </div>
        <div>
          <span class="span-formula"></span>
        </div>
        <div>
          <table class="table-pairs">
            <thead>
              <th>
                X
              </th>
              <th>
                Y
              </th>
            </thead>
            <tbody></tbody>
          </table>
        </div>
      </div>
      <div class="right-half">
        <canvas id="myChart"></canvas>
      </div>
    </div>
    <script src="/js/least-squares.js"></script>
  </body>
</html>

Ne creăm elementele:

  • Două intrări pentru perechile noastre, una pentru X și una pentru Y
  • Un buton pentru a adăuga acele valori într-un tabel
  • Un interval pentru a afișa formula curentă pe măsură ce se adaugă valori
  • Un tabel pentru a arăta perechile pe care le-am adăugat
  • Și o pânză pentru graficul nostru

De asemenea, importăm Chart.js bibliotecă cu un CDN și adăugați fișierele noastre CSS și JavaScript.

public / style.css

.container {
  display: grid; 
}

.left-half {
  grid-column: 1;
}

.right-half {
  grid-column: 2;
}

Adăugăm câteva reguli, astfel încât să avem intrările și tabelul la stânga și graficul la dreapta. Acest lucru profită de grila CSS.

public / minimum-squares.js

document.addEventListener('DOMContentLoaded', init, false);

function init() {
  const currentData = {
    pairs: [],
    slope: 0,
    coeficient: 0,
    line: [],
  };

  const chart = initChart();
}
 
function initChart() {
  const ctx = document.getElementById('myChart').getContext('2d');

  return new Chart(ctx, {
    type: 'scatter',
    data: {
      datasets: [{
        label: 'Scatter Dataset',
        backgroundColor: 'rgb(125,67,120)',
        data: [],
      }, {
        label: 'Line Dataset',
        fill: false,
        data: [],
        type: 'line',
      }],
    },
    options: {
      scales: {
        xAxes: [{
          type: 'linear',
          position: 'bottom',
          display: true,
          scaleLabel: {
            display: true,
            labelString: '(X)',
          },
        }],
        yAxes: [{
          type: 'linear',
          position: 'bottom',
          display: true,
          scaleLabel: {
            display: true,
            labelString: '(Y)',
          },
        }],
      },
    },
  });
}
Toate proprietățile graficului despre modul de coafare pot fi găsite în documentația lor aici

Și, în cele din urmă, ne inițializăm graficul. La început, ar trebui să fie gol deoarece nu am adăugat încă date la el.

Acum, dacă alergăm npm rulați server-debug și deschideți browserul nostru pe localhost: 5000 ar trebui să vedem așa ceva:

1611418031 389 Metoda de regresie a celor mai mici patrate Cum
Intrările noastre în stânga cu un buton de adăugare sau tabel cu doar antetele X și Y, în dreapta un grafic gol

Adăugarea funcționalității

Următorul pas este să faceți butonul „Adăugați” să facă ceva. În cazul nostru, dorim să realizăm:

  • Adăugați valorile X și Y în tabel
  • Actualizați formula atunci când adăugăm mai multe perechi (avem nevoie de cel puțin 2 perechi pentru a crea o linie)
  • Actualizați graficul cu punctele și linia
  • Curățați intrările, astfel încât să fie mai ușor să introduceți în continuare date

Adăugați valorile în tabel

public / minimum-squares.js

document.addEventListener('DOMContentLoaded', init, false);

function init() {
  const currentData = {
    pairs: [],
    slope: 0,
    coeficient: 0,
    line: [],
  };
  const btnUpdateGraph = document.querySelector('.btn-update-graph');
  const tablePairs = document.querySelector('.table-pairs');
  const spanFormula = document.querySelector('.span-formula');

  const inputX = document.querySelector('.input-x');
  const inputY = document.querySelector('.input-y');

  const chart = initChart();

  btnUpdateGraph.addEventListener('click', () => {
    const x = parseFloat(inputX.value);
    const y = parseFloat(inputY.value);

    updateTable(x, y);
  });
  
  function updateTable(x, y) {
    const tr = document.createElement('tr');
    const tdX = document.createElement('td');
    const tdY = document.createElement('td');

    tdX.innerHTML = x;
    tdY.innerHTML = y;

    tr.appendChild(tdX);
    tr.appendChild(tdY);

    tablePairs.querySelector('tbody').appendChild(tr);
  }
}

// ... rest of the code as it was

Primim toate elementele pe care le vom folosi în scurt timp și adăugăm un eveniment pe butonul „Adăugați”. Evenimentul respectiv va prelua valorile actuale și ne va actualiza vizual tabelul.

Trebuie să analizăm suma, deoarece obținem un șir. Va fi important pentru următorul pas când va trebui să aplicăm formula.

1611418032 358 Metoda de regresie a celor mai mici patrate Cum
Când apăsăm adăugare, ar trebui să vedem perechile pe masă

Faceți calculele

Toată matematica despre care vorbeam mai devreme (obținând media de X și Da, calculând b, și de calcul A) ar trebui acum transformat în cod. Vom afișa, de asemenea A și b valori, astfel încât să le vedem schimbându-se pe măsură ce adăugăm valori.

public / minimum-squares.js

// ... rest of the code as it was

btnUpdateGraph.addEventListener('click', () => {
  const x = parseFloat(inputX.value);
  const y = parseFloat(inputY.value);

  updateTable(x, y);
  updateFormula(x, y);
});

function updateFormula(x, y) {
  currentData.pairs.push({ x, y });
  const pairsAmount = currentData.pairs.length;

  const sum = currentData.pairs.reduce((acc, pair) => ({
    x: acc.x + pair.x,
    y: acc.y + pair.y,
  }), { x: 0, y: 0 });

  const average = {
    x: sum.x / pairsAmount,
    y: sum.y / pairsAmount,
  };

  const slopeDividend = currentData.pairs
    .reduce((acc, pair) => parseFloat(acc + ((pair.x - average.x) * (pair.y - average.y))), 0);
  const slopeDivisor = currentData.pairs
    .reduce((acc, pair) => parseFloat(acc + (pair.x - average.x) ** 2), 0);

  const slope = slopeDivisor !== 0
    ? parseFloat((slopeDividend / slopeDivisor).toFixed(2))
    : 0;

  const coeficient = parseFloat(
    (-(slope * average.x) + average.y).toFixed(2),
  );

  currentData.line = currentData.pairs
    .map((pair) => ({
      x: pair.x,
      y: parseFloat((coeficient + (slope * pair.x)).toFixed(2)),
    }));

  spanFormula.innerHTML = `Formula: Y = ${coeficient} + ${slope} * X`;
}

// ... rest of the code as it was

Nu există multe de spus despre cod aici, deoarece este toată teoria prin care am trecut mai devreme. Trecem în buclă valorile pentru a obține sume, medii și toate celelalte valori de care avem nevoie pentru a obține coeficientul (A) și panta (b).

1611418032 912 Metoda de regresie a celor mai mici patrate Cum
Intervalul, astfel încât să putem afișa formula și să o vedem schimbându-se pe măsură ce adăugăm valori

Avem perechi și linia în actual variabilă, astfel încât să le folosim în pasul următor pentru a ne actualiza graficul.

Actualizați graficul și curățați intrările

public / minimum-squares.js

// ... rest of the code as it was

btnUpdateGraph.addEventListener('click', () => {
  const x = parseFloat(inputX.value);
  const y = parseFloat(inputY.value);

  updateTable(x, y);
  updateFormula(x, y);
  
  updateChart();
  
  clearInputs();
});

function updateChart() {
  chart.data.datasets[0].data = currentData.pairs;
  chart.data.datasets[1].data = currentData.line;

  chart.update();
}
  
function clearInputs() {
  inputX.value="";
  inputY.value="";
}

// ... rest of the code as it was

Actualizarea graficului și curățarea intrărilor de X și Da este foarte simplu. Avem două seturi de date, primul (poziția zero) este pentru perechile noastre, așa că arătăm punctul pe grafic. A doua (poziția unu) este pentru linia noastră de regresie.

Trebuie să ne apucăm de instanță și să apelăm Actualizați deci vedem că noile valori sunt luate în considerare.

1611418032 620 Metoda de regresie a celor mai mici patrate Cum
Sunt necesare cel puțin trei valori, astfel încât să putem lua orice fel de informații despre grafic

Adăugarea unui stil

Ne putem schimba aspectul puțin, astfel încât să fie mai ușor de gestionat. Nimic major, servește doar ca un memento că putem actualiza interfața de utilizare în orice moment

public / style.css

.container {
  display: grid; 
}

.left-half {
  grid-column: 1;
}

.right-half {
  grid-column: 2;
}

.pairs-style input[type="number"],
.pairs-style button {
  margin: 5px 0px;
}

.table-pairs {
  border-collapse: collapse;
  width: 100%;
}

.table-pairs td {
  text-align: center;
}

.table-pairs,
.table-pairs th,
.table-pairs td {
  margin: 10px 0px;
  border: 1px solid black;
}

public / index.html

<html>
  <head>
    <title>Least Squares Regression</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/Chart.min.js"></script>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div class="container">
      <div class="left-half">
        <div class="pairs-style">
          <div>
            <input type="number" class="input-x" placeholder="X">
          </div>
          <div>
            <input type="number" class="input-y" placeholder="Y">
          </div>
          <button class="btn-update-graph">Add</button> 
        </div>
        <div>
          <span class="span-formula">Formula: Y = a + b * X</span>
        </div>
        <div>
          <table class="table-pairs">
            <thead>
              <th>
                X
              </th>
              <th>
                Y
              </th>
            </thead>
            <tbody></tbody>
          </table>
        </div>
      </div>
      <div class="right-half">
        <canvas id="myChart"></canvas>
      </div>
    </div>
    <script src="/js/least-squares.js"></script>
  </body>
</html>
1611418033 798 Metoda de regresie a celor mai mici patrate Cum
Nu este o mare schimbare, dar cel puțin elementele sunt puțin mai bine aliniate

Dovada de concept

1611418033 235 Metoda de regresie a celor mai mici patrate Cum
Adăugăm aceleași valori ca mai devreme în teorie și obținem același grafic și formulă! : D

Observații finale

Din motive de scurtă durată, am decupat o mulțime care poate fi luată ca un exercițiu pentru a îmbunătăți considerabil proiectul. De exemplu:

  • Adăugați verificări pentru valori goale și altele asemenea
  • Faceți-o astfel încât să putem elimina datele pe care le-am inserat greșit
  • Adăugați o intrare pentru X sau Y și aplicați formula de date curentă pentru a „prezice viitorul”, similar cu ultimul exemplu al teoriei

Indiferent, prezicerea viitorului este un concept distractiv, chiar dacă, în realitate, cel mai mult putem spera să prezicem este o aproximare bazată pe punctele de date din trecut.

Este o formulă puternică și dacă construiești orice proiect folosindu-l, mi-ar plăcea să-l văd.

Sper că acest articol a fost util pentru a servi ca introducere la acest concept. Codul folosit în articol se găsește în GitHub aici.

Ne vedem în următoarea, între timp, mergi la cod ceva!