Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 105 additions & 2 deletions plinko/score.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,111 @@
const outputs = [];
// determine the corellation between bucket and predictionPoint

function onScoreUpdate(dropPosition, bounciness, size, bucketLabel) {
// Ran every time a balls drops into a bucket
outputs.push([dropPosition, bounciness, size, bucketLabel]);
}

function runAnalysis() {
// Write code here to analyze stuff
const testSetSize = 100;
const k = 10;
const colNames = ['Drop Position', 'Bounciness', 'Ball Size'];

// vary k using range
_.range(0, 3).forEach((feature) => {
const data = _.map(outputs, (row) => [row[feature], _.last(row)]);

const [testSet, trainingSet] = splitDataSet(minMax(data, 1), testSetSize);
const accuracy = _.chain(testSet)
.filter((testPoint) => knn(trainingSet, _.initial(testPoint), k) === _.last(testPoint))
.size()
.divide(testSetSize)
.value();

console.log(`k(${k}) Accuracy for ${colNames[feature]}: ${accuracy * 100}%`);
});
}

function knn(data, point, k) {
// K-Nearest Neighbor Algorithm
return (
_.chain(data)
// [[distance(dropPosition, predictionPoint), bucketLabel],[72,4],[227,5]]
.map((row) => {
return [distance(_.initial(row), point), _.last(row)];
})
// sort by drop position
.sortBy((row) => row[0])
// Gets the top 'k' results from sorted list
.slice(0, k)
// counts frequency of buckets
// e.g., {"3":1,"4":2}
.countBy((row) => row[1])
// e.g., [["3",1],["4",2]]
// converts the countBy obj to an multidimensional array
.toPairs()
// sorts so that the most frequent is the last array element
.sortBy((row) => row[1])
// get the last array element of ["bucket", frequency]
.last()
// e.g., "4"
// get the bucket number (first element)
.first()
// e.g., 4
// convert the string "4" to int 4
.parseInt()
// end the chain and return the value
.value()
);
}

function distance(pointA, pointB) {
// pointA/B are arrays
// employing the pythagorean therom to solve a multidimensional point distance
_.chain(pointA)
// takes each value at the same index of each array and creates a new zipped
// array:
// [[pointA[0], pointB[0]], [pointA[1], pointB[1]] ... ]
.zip(pointB)
// subtracts b from a
.map(([a, b]) => (a - b) ** 2)
// sums the squares
.sum()
// returns the squareroot of the sum
.value() ** 0.5;
}

function splitDataSet(data, testCount) {
const shuffled = _.shuffle(data);

const testSet = _.slice(shuffled, 0, testCount);
const trainingSet = _.slice(shuffled, testCount);

return [testSet, trainingSet];
}

function minMax(data, featureCount) {
const clonedData = _.cloneDeep(data);

// iterate over each feature (independent variables)
for (let i = 0; i < featureCount; i++) {
const column = clonedData.map((row) => row[i]);
const min = _.min(column);
const max = _.max(column);

// iterate over each row [j] in clonedData
// and normalize each feature [i]
// a row would look something like :
//
// [ position, bounciness, ballSize, bucketName ]
//
// where bucketName is a label and not normalized
for (let j = 0; j < clonedData.length; j++) {
clonedData[j][i] = (clonedData[j][i] - min) / (max - min);
if (max - min === 0) {
clonedData[j][i] = 0;
}
}
}

return clonedData;
}
62 changes: 62 additions & 0 deletions regressions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
require('@tensorflow/tfjs-node');
const tf = require('@tensorflow/tfjs');
const loadCSV = require('./load-csv');
const LinearRegression = require('./linear-regression');
const plot = require('node-remote-plot');
const { initial } = require('lodash');

let { features, labels, testFeatures, testLabels } = loadCSV('./cars.csv', {
shuffle: true,
splitTest: 50,
dataColumns: ['displacement', 'horsepower', 'weight', 'acceleration'],
labelColumns: ['mpg'],
});

const initLR = 0.1;
const regression = new LinearRegression(features, labels, {
learningRate: initLR,
iterations: 30,
batchSize: 1,
});

regression.train();
/**
* weights tensor has a [2,1] shape and looks like this:
* [
* [0],
* [0]
* ]
*/
const r2 = regression.test(testFeatures, testLabels);
plot({
x: regression.mseHistory.reverse(),
xLabel: 'Iterations',
yLabel: 'MSE',
});
console.log('R2 : ', r2, ' initLR: ', initLR, ' iterations: ', regression.options.iterations);

litersToCID = (liters) => {
// There are 61 cubic inches in a liter
return liters * 61;
};

/**
* mpg, cyl, displacement, hp, wt, acc
* [13,8,400,175,2.57,12],
* [11,8,400,150,2.5,14],
* [12,8,383,180,2.48,11],
* [12,8,429,198,2.48,11],
* [12,8,455,225,2.48,11],
* [12,8,400,167,2.45,12],
* [13,8,400,170,2.37,12],
*/
vehicles = [
[400, 175, 2.57, 12],
[400, 150, 2.5, 14],
[383, 180, 2.48, 11],
[429, 198, 2.48, 11],
[455, 225, 2.48, 11],
[400, 167, 2.45, 12],
[400, 170, 2.37, 12],
];
regression.predict(vehicles).print();
Loading