Last active
April 16, 2016 11:45
-
-
Save gvergnaud/7c2e340add933727594f71deb1ab3df5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ----------------------------------------- * | |
Learning Machin Learning | |
* ----------------------------------------- */ | |
import { compose, map, chain, range } from 'ramda' | |
// Result = { a :: Int, b :: Int, cost :: Number } | |
// Data = [Int, Int] | |
// Tupple = [Int, Int] | |
// findBestResult :: [Result] -> Result | |
const findBestResult = (results) => | |
results.reduce( | |
(bestResult, result) => result.cost < bestResult.cost ? result : bestResult, | |
{ cost: Infinity } | |
) | |
// getSquareError :: Tupple -> Data -> Int | |
const getSquareError = ([a, b]) => ([x, y]) => | |
((a + b * x) - y) ** 2 | |
// sum :: List a -> (a -> Int) -> Int | |
const sum = (list, transformer) => | |
list.reduce((acc, item) => acc + transformer(item), 0) | |
// getResult :: List Data -> Tupple -> Result | |
const getResult = dataSet => ([a, b]) => ({ | |
a, | |
b, | |
cost: sum(dataSet, getSquareError([a, b])) / (2 * dataSet.length) | |
}) | |
// resultToTupple :: Result a b -> Tupple a b | |
const resultToTupple = ({ a, b }) => [a, b] | |
const log = x => { | |
console.log(x) | |
return x | |
} | |
// List Data -> List Tupple -> Result | |
const getBestTupple = dataSet => compose( | |
resultToTupple, | |
log, | |
findBestResult, | |
map(getResult(dataSet)) | |
) | |
// granularRange :: Number a -> Number b -> Number -> List [0..a, 0..b] | |
const granularRange = (start, end, granularity) => | |
map(x => x / granularity, range(start * granularity, end * granularity)) | |
// createTuppleRange List a -> List b -> List [a, b] | |
const createTuppleRange = (as, bs) => | |
chain(a => map(b => [a, b], bs), as) | |
// linearRegression :: List Data -> List Tupple -> (a -> Int) -> Int | |
export default function linearRegression(dataSet) { | |
const getBestTuppleForDataSet = (a, b, changeA) => { | |
const [bestA, bestB] = getBestTupple(dataSet)( | |
createTuppleRange( | |
granularRange(a.start, a.end, a.granularity), | |
granularRange(b.start, b.end, b.granularity) | |
) | |
) | |
if (a.granularity >= 100) return [bestA, bestB] | |
return getBestTuppleForDataSet( | |
changeA | |
? { start: bestA - 1 / a.granularity, end: bestA + 1 / a.granularity, granularity: a.granularity * 10 } | |
: a, | |
{ start: bestB - 1 / b.granularity, end: bestB + 1 / b.granularity, granularity: b.granularity * 10 }, | |
b.granularity >= 1 | |
) | |
} | |
const [a, b] = getBestTuppleForDataSet( | |
{ start: -1000, end: 1000, granularity: .01 }, | |
{ start: -1000, end: 1000, granularity: .01 } | |
) | |
return x => a + b * x | |
} | |
/* ----------------------------------------- * | |
Usage | |
* ----------------------------------------- */ | |
const trainingSet = [ | |
{ | |
size: 2104, | |
price: 460 | |
}, | |
{ | |
size: 1416, | |
price: 232 | |
}, | |
{ | |
size: 1534, | |
price: 315 | |
}, | |
{ | |
size: 852, | |
price: 178 | |
}, | |
{ | |
size: 852, | |
price: 178 | |
}, | |
{ | |
size: 2500, | |
price: 500 | |
}, | |
{ | |
size: 2320, | |
price: 423 | |
} | |
] | |
const cleanData = map(({ size, price }) => [size, price]) | |
const h = linearRegression(cleanData(trainingSet)) | |
console.log(`size: ${1503}, estimated price ${h(1503)}`) | |
console.log(`size: ${2000}, estimated price ${h(2000)}`) | |
console.log(`size: ${1000}, estimated price ${h(1000)}`) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment