Skip to content

Commit

Permalink
Merge pull request #1 from nikolas-virionis/correlation
Browse files Browse the repository at this point in the history
Correlation
  • Loading branch information
nikolas-virionis committed Nov 27, 2021
2 parents 9fcd545 + b7f2355 commit 4d5d630
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 7 deletions.
49 changes: 45 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,30 @@ An npm package to make it easier to deal with a handful of values, and try to mo
npm install linear-regression-model
~~~
- Importing the module<br>

First, there is the Linear Regression model between two different datasets, in relation to each other<br>
Which will look like something similar to this:
~~~ javascript
const {LinearModel} = require("linear-regression-model");
// if it is preferred not to use destructuring, or constants use
// var LinearModel = require("linear-regression-model").LinearModel;
// var LinearModel = require("linear-regression-model-model").LinearModel;
~~~
Or if the use case for this is pending more to the behavior of one single dataset<br>
overtime, this will be more fitting:
~~~ javascript
const {LinearModelOverTime} = require("linear-regression-model");
// if it is preferred not to use destructuring, or constants use
// var LinearModelOverTime = require("linear-regression").LinearModelOverTime;
// var LinearModelOverTime = require("linear-regression-model").LinearModelOverTime;
~~~
And to use the Correlation class, it will be some like this:
~~~ javascript
const {Correlation} = require("linear-regression-model");
// if it is preferred not to use destructuring, or constants use
// var Correlation = require("linear-regression-model").Correlation;
~~~
Although if your use case is the overtime behaviour, i would advise the use<br>
of the [method](#correlation) in the LinearModelOverTime class<br>
But if you are using the LinearModel class, it is really up to you
## Instantiate the classes
~~~ javascript
const lm = new LinearModel([1, 2, 3, 2, 3, 4], [3, 4, 5, 4, 5, 6]);
Expand All @@ -47,7 +57,13 @@ overtime, this will be more fitting:
//dependent variable: y changes according to how x changes, the later is
// generated automatically for a better representation of the behavior overtime
~~~

or
~~~ javascript
const corr = new Correlation([1, 2, 3, 2, 3, 4], [3, 4, 5, 4, 5, 6]);
// mandatory to pass two, same sized, all number, arrays, being the
// orientation (x, y), being x the independent variable and y the
// dependent: y changes according to how x changes, basically
~~~
Let it be clear, it is necessary to pass all number arrays, with more than 1 value,<br>
in order for the algorithm to work properly, it will try to convert all the elements<br>
to numbers, but if that is not possible, the code will crash.
Expand All @@ -61,7 +77,7 @@ if the X axis dataset is informed or generated, therefore, the method will be sh
the LinearModel class, the use for the LinearModelOverTime class is the exact same tough

- Just to make it clear, it is necessary to pass the parameters as said in [instatiating the class](#instantiate-the-classes), above

## LinearModel and LinearModelOverTime
- getDataset
~~~ javascript
lm.getDataset()
Expand Down Expand Up @@ -145,3 +161,28 @@ the LinearModel class, the use for the LinearModelOverTime class is the exact sa
// and an actual js function to make predictions, for example
// function(x): returns Y, using the same method as the dataset
~~~
### Correlation
- getCorrelation
~~~ javascript
lm.getCorrelation()
// returns the correlation between the datasets
~~~

## Correlation (class)
- (static) getMean
~~~ javascript
Correlation.getMean(dataset)
// returns the mean of the dataset
~~~
- (static) getDifferenceFromMeanAndElements
~~~ javascript
Correlation.getDifferenceFromMeanAndElements(dataset)
// returns the difference between the mean and the elements
// of the dataset, so can be used to calculate variance,
// for example
~~~
- getCorrelation
~~~ javascript
corr.getCorrelation()
// returns the correlation between the datasets
~~~
149 changes: 146 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @module linear-regression
* @module linear-regression-model
* Represents the linear model class
* of a dataset behaviour overtime
* @author Nikolas B Virionis <nikolas.virionis@bandtec.com.br>
Expand Down Expand Up @@ -312,10 +312,22 @@ class LinearModelOverTime {
function: x => x * this.getSlope() + this.getLinearCoefficient()
};
}

/**
* @method
* shortcut to get the correlation of the datasets
* @returns {number}
* returns the correlation between the two datasets
* in an easier way
*/
getCorrelation() {
let corr = new Correlation(this._xValues, this._data);
return corr.getCorrelation();
}
}

/**
* @module linear-regression
* @module linear-regression-model
* Represents the linear model class
* of a dataset behaviour in relation
* to its counterpart
Expand Down Expand Up @@ -364,4 +376,135 @@ class LinearModel extends LinearModelOverTime {
}
}

module.exports = {LinearModelOverTime, LinearModel};
/**
* @module linear-regression-model
* Represents the correlation class
*
* @author Nikolas B Virionis <nikolas.virionis@bandtec.com.br>
*/
class Correlation {
/**
* @attributes
* - datasetY
* - datasetX <br>
* Both represent the datasets used
* for the correlation
*/
datasetY;
datasetX;

/**
* @constructor
* @param {number[]} datasetX
* @param {number[]} datasetY
* The datasets the correlation is made with
*/
constructor(datasetX, datasetY) {
if (!datasetX || !datasetY) {
throw "Two arrays are necessary for Correlation";
}
if (datasetX.length != datasetY.length) {
throw "The arrays have different lengths, which is not allowed";
}
if (!Array.isArray(datasetX) || !Array.isArray(datasetY)) {
throw "Constructor parameter is not an array";
}
if (datasetX.length < 2) {
throw "In order to design a linear model, you must provide at least 2 data points";
}
try {
datasetY = datasetY.map(el => Number(el));
datasetX = datasetX.map(el => Number(el));
} catch (e) {
throw `Some value in one of the datasets is invalid, or impossible to convert to number, \nError: ${e}`;
}
this.datasetY = datasetY;
this.datasetX = datasetX;
}

/**
* gets the mean of the dataset
* @param {number[]} dataset
* @returns {number} the mean, average, of the dataset
*/
static getMean(dataset) {
return Correlation.#sumDataset(dataset) / dataset.length;
}

/**
* gets the difference between the mean and the elements of the dataset
* @param {number[]} dataset
* @returns {number[]}
*/
static getDifferenceFromMeanAndElements(dataset) {
let data = dataset.map(
element => element - Correlation.getMean(dataset)
);
return data;
}

/**
* creates the secondary lists, used for the correlation
* @returns {number[][]} the secondary lists
*/
#getSecondaryLists() {
let dataY = Correlation.getDifferenceFromMeanAndElements(this.datasetY);
let dataX = Correlation.getDifferenceFromMeanAndElements(this.datasetX);
return this.#fillSecondaryLists(dataX, dataY);
}
/**
* fills the secondary lists, used for the
* correlation, with their respective data
* @param {number[]} dataX
* @param {number[]} dataY
* @returns {number[][]} the secondary lists
*/
#fillSecondaryLists(dataX, dataY) {
let ab = [];
let a2 = [];
let b2 = [];
for (let index in dataX) {
ab.push(dataX[index] * dataY[index]);
a2.push(dataX[index] ** 2);
b2.push(dataY[index] ** 2);
}
return [ab, a2, b2];
}

/**
* sums all the values of a dataset
* @param {number[]} dataset
* @returns {number}
*/
static #sumDataset(dataset) {
return dataset.reduce((sum, element) => sum + element, 0);
}

/**
* sums the secondary dataset values
* @param {number[]} ab
* @param {number[]} a2
* @param {number[]} b2
* @returns {number[]}
*/
#getSumOfCorrDatasets(ab, a2, b2) {
let sumAb = Correlation.#sumDataset(ab);
let sumA2 = Correlation.#sumDataset(a2);
let sumB2 = Correlation.#sumDataset(b2);
return [sumAb, sumA2, sumB2];
}

/**
* ends the formula of the correlation
* and returns its value
* @returns {number} the correlation itself
*/
getCorrelation() {
let [ab, a2, b2] = this.#getSecondaryLists();
let [sumAb, sumA2, sumB2] = this.#getSumOfCorrDatasets(ab, a2, b2);

return sumAb / (sumA2 * sumB2) ** (1 / 2);
}
}

module.exports = {LinearModelOverTime, LinearModel, Correlation};

0 comments on commit 4d5d630

Please sign in to comment.