Cubic Regression (best fit line) in JavaScript - javascript

I'm having the worst time trying to find a JavaScript code that could allow me to do cubic regressions. Would write it myself, but my understanding of polynomial math is, well, suboptimal.
So, here's what I'm looking for. Given an input of an array of arrays, where the internal array would be [x,y], the function would give me an output in the form of an array with four parameters - [a,b,c,d], where a, b, c, and d are parameters of the equation y = ax^3 + bx^2 + cx + d.
Example:
Input is an array like this [[2,5],[5,10],[07,15],[12,20],[20,25],[32,30],[50,35]].
Which essentially is the representation of a table:
| x | y |
|-----------------|
| 02 | 05 |
| 05 | 10 |
| 07 | 15 |
| 12 | 20 |
| 20 | 25 |
| 32 | 30 |
| 50 | 35 |
Now, the output would be [0.000575085,-0.058861065,2.183957502,1.127605507]. These are the a, b, c, and d parameters of the cubic function.
(FYI, the output I got by using Excel's LINEST function and running it on the above set of numbers using an array function {1,2,3}).
How could this be done? Huge thanks in advance for any guidance.
Best,
Tom

Here's a real, working bit of code to solve that cubic using the numeric.js library's uncmin unconstrained minimiser as a least squares problem (jsbin here):
var data_x = [2,5,7,12,20,32,50];
var data_y = [5,10,15,20,25,30,35];
var cubic = function(params,x) {
return params[0] * x*x*x +
params[1] * x*x +
params[2] * x +
params[3];
};
var objective = function(params) {
var total = 0.0;
for(var i=0; i < data_x.length; ++i) {
var resultThisDatum = cubic(params, data_x[i]);
var delta = resultThisDatum - data_y[i];
total += (delta*delta);
}
return total;
};
var initial = [1,1,1,1];
var minimiser = numeric.uncmin(objective,initial);
console.log("initial:");
for(var j=0; j<initial.length; ++j) {
console.log(initial[j]);
}
console.log("minimiser:");
for(var j=0; j<minimiser.solution.length; ++j) {
console.log(minimiser.solution[j]);
}
I get the results:
0.0005750849851827991
-0.05886106462847641
2.1839575020602164
1.1276055079334206
To explain: we have a function 'cubic', which evaluates the general cubic function for a set of parameters params and a value x. This function is wrapped to create the objective function, which takes a set of params and runs each x value from our data set through the target function and calculates the sum of the squares. This function is passed to uncmin from numeric.js with a set of initial values; uncmin does the hard work and returns an object whose solution property contains the optimised parameter set.
To do this without the global variables (naughty!), you can have an objective function factory thus:
var makeObjective = function(targetFunc,xlist,ylist) {
var objective = function(params) {
var total = 0.0;
for(var i=0; i < xlist.length; ++i) {
var resultThisDatum = targetFunc(params, xlist[i]);
var delta = resultThisDatum - ylist[i];
total += (delta*delta);
}
return total;
};
return objective;
};
Which you can use to manufacture objective functions:
var objective = makeObjective(cubic, data_x, data_y); // then carry on as before
Knowing how to do this practically would be of great help to a lot of people, so I'm glad this has come up.
Edit: Clarification on cubic
var cubic = function(params,x) {
return params[0] * x*x*x +
params[1] * x*x +
params[2] * x +
params[3];
};
Cubic is being defined as a function which takes an array of parameters params and a value x. Given params, we can define a function f(x). For a cubic, that is f(x) = a x^3 + b x^2 + c x + d so there are 4 parameters ([0] to [3]), and given those 4 param values we have a single function f(x) with 1 input x.
The code is structured to allow you to replace cubic with another function of the same structure; it could be linear with 2 parameters:
var linear = function(params, x) {
return params[0]*x + params[1];
};
The rest of the code will look at the length of params in order to know how many parameters need modifying.
Note that this whole piece of code is trying to find the set of parameter values which produce a curve which best fits all the data; if you wanted to find a fit for the last 4 points of some data, you would pass only those values in data_x and data_y.

I'd formulate this as a least squares problem. Let M be the n×4 matrix formed like this:
x_1^3 x_1^2 x_1 1
x_2^3 x_2^2 x_2 1
⋮ ⋮ ⋮
x_n^3 x_n^2 x_n 1
Then compute the 4×4 matrix A=MT⋅M and the 4×1 column vector b=MT⋅y and solve the linear system of equations Aξ=b. The resulting vector ξ will contain your coefficients a through d.
The above description makes it easy to understand what is going on, mathematically. For implementation, particularly for very large n, the above approach might however be infeasible. In those cases, you can build A and b directly, without explicitely constructing M. For example, A1,2=sum(x_i^3 * x_i^2 for all i). So you can iterate over all i and add the corresponding values to the corresponding matrix and vector entries.

Related

Explaining functions of Vigenère cipher

i found the following code at http://rosettacode.org for the Vigenère cipher and i would like to undestand it better.
Could someone explain me what the single lines of code in function ordA(a) and in function(a) do?
function ordA(a) {
return a.charCodeAt(0) - 65;
}
// vigenere
function vigenere2(text, key, decode) {
var i = 0, b;
key = key.toUpperCase().replace(/[^A-Z]/g, '');
return text.toUpperCase().replace(/[^A-Z]/g, '').replace(/[A-Z]/g, function(a) {
b = key[i++ % key.length];
return String.fromCharCode(((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65));
});
}
I'm not sure if that is supposed to be example code, but it mainly shows how not to program. Smart decisions are being made, but obviously the problem decomposition, variable naming and documentation leave a lot to be desired. Repeated code, convoluted lines, unexplained code fragments, the list goes on. Decode is a boolean, but the opposite of encryption is decryption not decoding. This code was made to not understand what is going on; what it does on the Rosetta site is mind-boggling in that respect.
returns an index in the English alphabet or ABC, assuming uppercase characters, 0 to 25 instead of 1 to 26 (because you can do modular calculations with zero indexing, not with one based indexing)
return a.charCodeAt(0) - 65;
function definition that takes a plaintext or ciphertext, a key which may be smaller than the plaintext and a Boolean to indicate if we're encoding or decoding
function vigenere2(text, key, decode)
index in plaintext and variable b, which will hold a character of the key for the index
var i = 0, b;
converts the key to uppercase and removed all characters not in the uppercase alphabet as well
key = key.toUpperCase().replace(/[^A-Z]/g, '');
this line is too long obviously; it converts the text to uppercase and removes the non-alphabet characters again
then it replaces the characters in the string using the function defined in the second argument of replace
return text.toUpperCase().replace(/[^A-Z]/g, '').replace(/[A-Z]/g, function(a) {
take the next character of the key in round robin fashion, using the modulus operator, update the index afterwards
b = key[i++ % key.length];
too much going on here, very bad program decomposition; in order of execution:
(decode ? 26 - ordA(b) : ordA(b)): calculate a number in the range to update the index of the plaintext character; use the opposite value for decryption (wrongly called "decoding" here)
(ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 perform the addition with the calculated number, reduce to 0 to 25 (i.e. when reaching Z continue with A and vice versa)
((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65) add 65 so the index is converted back into the ASCII index of uppercase characters, using two completely spurious parentheses
finally, returns a string from one character code result, otherwise + will be addition instead of concatenation
return String.fromCharCode(((ordA(a) + (decode ? 26 - ordA(b) : ordA(b))) % 26 + 65));
well, it needed to end
});
}
Let's show another way of programming this, using well named variables, functions for reused code and regular expressions that badly need a name to explain what they do.
var ALPHABET_SIZE = 'Z'.charCodeAt(0) - 'A'.charCodeAt(0) + 1;
var encrypted = vigenere(false, "B", "Zaphod Breeblebox");
document.body.append('<div>' + encrypted + '</div>');
var decrypted = vigenere(true, "B", encrypted);
document.body.append('<div>' + decrypted + '</div>');
function vigenere(decrypt, key, text) {
key = toJustUppercase(key);
text = toJustUppercase(text);
var textOffset = 0;
// iterate over all characters, performing the function on each of them
return text.replace(/[A-Z]/g, function(textChar) {
var keyChar = key[textOffset++ % key.length];
var cryptedChar = substituteCharacter(decrypt, keyChar, textChar);
return cryptedChar;
});
}
function substituteCharacter(decrypt, keyChar, textChar) {
var keyIndex = charToABCIndex(keyChar);
if (decrypt) {
// create the opposite of the encryption key index
keyIndex = ALPHABET_SIZE - keyIndex;
}
var textIndex = charToABCIndex(textChar);
// the actual Vigenere substitution, the rest is just indexing and conversion
var substitutedIndex = (textIndex + keyIndex) % ALPHABET_SIZE;
var substitutedChar = abcIndexToChar(substitutedIndex);
return substitutedChar;
}
function toJustUppercase(text) {
return text.toUpperCase().replace(/[^A-Z]/g, '')
}
function charToABCIndex(charValue) {
return charValue.charCodeAt(0) - 'A'.charCodeAt(0);
}
function abcIndexToChar(index) {
return String.fromCharCode(index + 'A'.charCodeAt(0));
}
Too many functions you say? Not really, I've not implemented ord and chr, or vigenereEncrypt and viginereDecrypt to make it even easier to read.

Why am I getting undefined when putting a string of html to the main page using jQuery?

I'm fairly new to JavaScript and jQuery so any other advice you might have please leave in a comment below. I am making a card game to be played on a single screen in javascript.
Inside the div for id playerHand, I use a javascript function to output the hand of the current player's turn. Whenever I output the current player's hand, I get an output in that div like so:
undefined/ 6H / AD / 7H / 5H / 6S / KC / 8C / 10H / AC / 2H / 8S / 2D / 3S
The hand is made of 13 cards(denoted by numbers 2-10 and J, Q, K, A with a letter for hearts, spades, clubs and diamonds). All 13 cards print out to the div correctly but this random undefined thing is unexpected. The JavaScript function used to output this information is below.
JavaScript jQuery function:
function addHand() {
var htmlString;
for(i = 0; i < hands[currentPlayersTurn].handArray.length; i++) {
htmlString += "/ "+ hands[currentPlayersTurn].handArray[i].name +" ";
}
$("#playerHand").html(htmlString);
}
Look here:
var htmlString;
htmlString's initial "value" is undefined.
Then you stringise it via string concatenation, and keep adding to that initial value. It's neither "random" nor "unexpected"; it's what you programmed into the computer.
You probably meant:
var htmlString = "";
so as to begin with the empty string.
Your issues is with var htmlString since you do not initialize it. Though even if you set to empty string your output won't be as you expect because you will then just replace undefined/string/string/string with /string/string/string. A better approach would be to push the list of names into an array and then join them on /.
function addHand() {
var htmlList = [];
for(var i = 0; i < hands[currentPlayersTurn].handArray.length; i++) {
htmlList.push(hands[currentPlayersTurn].handArray[i].name);
}
$("#playerHand").html(htmlList.join(" / "));
}

How Do I Use Both Math.max() and Math.min() to bound my dragger

I'm building a horizontally dragging page layout. There are 3 columns, with two dragging objects. Everything is working fine except setting a max/min value for the drag.
The layout looks like this, with the two dragging bars either side of colB.
---------------------------
colA | colB | colC
| |
| |
| |
| |
| |
| |
| |
| |
I need to set it so that colA's dragger's maximum width (which is its left value) is equal to colC's dragger. Likewise, ColC's minimum needs to be colA's draggers' left value.
The function looks like this:
function doDragA(e) {
dragA.style.left = (e.clientX) + 'px';
}
function doDragC(e) {
dragC.style.left = (e.clientX) + 'px';
}
and I'm trying to do something like this:
function doDragA(e) {
var posC = parseInt(document.defaultView.getComputedStyle(dragC).left, 10);
dragA.style.left = (math.max(posC), math.min(0)) e.clientX + 'px';
}
function doDragC(e) {
var posA = parseInt(document.defaultView.getComputedStyle(dragA).left, 10);
dragC.style.left = (math.max(0), math.min(posA)) e.clientX + 'px';
}
But i'm getting syntax errors. I've console logged the values and they come through, it's just the math max/min syntax I'm getting wrong.
Firstly javascript is case sensitive, and the math object is Math, not math.
Secondly, the usage of min and max is to supply a list of arguments, not just one - it returns the answer to 'what is the value of highest/lowest of these?'.
Assuming you want the value of e.clientX bounded by some values valueMax and valueMin:
var valueUpToMax = Math.min(valueMax, e.clientX);
var valueAtLeastMin = Math.max(valueMin, e.clientX);
// so we can combine those to bound on both sides:
var boundedValue = Math.max(valueMin, Math.min(valueMax, e.clientX));
It seems like they should be the other way around; we limit to a maximum value by using Math.min, but it's because we are limiting to a maximum not trying to get a maximally high number.
The general principle is to use functions like in math:
c = f(a, b);
e = g(c, d);
-> e = g( f(a, b), d);

number incrementing in Angular.js

I'm attempting to build an app that calculates sales metrics. I have run into an unusual problem in my build.
Part of the app allows users to increase/decrease a variable by 5% and then see how that will effect an overall metric. It also allows the user to see the percentage increase/decrease.
I have the functionality working roughly as intended, however if I enter a number lower than 20 into the input and then try in increase it with my incrementing function it only increments once and then stops.
If the number I enter into the input is 20 or greater it increments in the intended way.
Below is my angular code:
function controller ($scope) {
$scope.firstNumber = 0;
$scope.firstPercent = 0;
$scope.increase = function(id) {
var A = parseInt(id);
var B = A * 5/100;
var C = 0;
var C = A + B;
if (id === $scope.firstNumber) {
$scope.firstNumber = C;
$scope.firstPercent = $scope.firstPercent + 5;
}
};
$scope.decrease = function(id) {
var A = parseInt(id);
var B = A * 5/100;
var C = 0;
var C = A - B;
if (id === $scope.firstNumber) {
$scope.firstNumber = C;
$scope.firstPercent = $scope.firstPercent - 5;
}
};
I can't see anything wrong with my maths, my thinking is that perhaps I'm approaching angular in the wrong way. However I'm not sure.
I have put together a fiddle that shows the full code.
jsFiddle
I have updated the fiddle to use parseFloat. Seems like the numbers are incrementing now.
var A = parseFloat(id);
http://jsfiddle.net/kjDx7/1/
The reason why it was working with values above 20 was that it was just reading the part before decimals each time it tried to increase. So 20 became 21 and 22.05 and so on. As long the the value before decimal kept changing, it showed different (but incorrect) answers.
On the other hand, 10 became 10.5 which when parsed yielded 10. As you can see, this cycle continued endlessly.
The reason why you face the issue is because 5% of anything less than or equal to 20 is less than or equal to 1.
When you parseInt() the value, you always end up with the same number again.
Take 15 for example.
5% of 15 = 15.75
After parseInt(), you get the value 15 again.
You use the same value to increment / decrement each time.
Hence for values below 20, you don't get any changes.
As #Akash suggests, use parseFloat() instead - or why even do that when the value that you get is float anyway
I made a fork of your fiddle. I'm not completely sure what you want to achive.
Take a look at this fiddle.
$scope.increase = function() {
$scope.firstPercent = $scope.firstPercent + 5;
var A = $scope.firstNumber;
var B = (A / 100) * $scope.firstPercent;
var C = A + B;
$scope.firstNumberWithPercent = C;
};
update
After posting, i see that question is already answered. But is this what you really want? When you hit increase, it takes 5 % off of the number in the input field. That is ok, but when you hit decrease after that, it takes 5 % off the number in the same field. So your starting point is different.
100 + 5/100 = 105
105 - 5/105 = 99,75

Javascript Big Decimal - Nth Root

Recently I run into the well known floating point precision errors of Javascript. Usually I would avoid floating point calculations on the thin client & rather leave it to the back-end.
I started using the big.js library created by Michael Mclaughlin. Though it has a square-root method/function, it does not have a nth-root methods/function nor does the power function support fraction values as arguments.
So I was wondering if anyone using the library has extended it to have such a function or at least use it to calculate accurate nth-root results.
Michael Mclaughlin suggested that I implement such a function similar in structure to the square-root function. However my attempts at understanding the logic proofed my maths-disability, resulting in simple calculations yielding very wrong results.
Using the algorithm on Rosetta Code also yields incorrect results.
So I was wondering if anyone using the library has extended it to have such a function or at least use it to calculate accurate nth-root results.
Here is the code to my last attempt:
P['nthrt'] = P['nthroot'] = function (n, prec)
{
var negate, r,
x = this,
xc = x['c'],
i = x['s'],
e = x['e'];
// Argument defaults
n = n || 2;
prec = prec || 12;
// Zero?
if ( !xc[0] ) {
return new Big(x)
}
// Negative?
negate = ( n % 2 == 1 && i < 0 );
// Estimate.
r = new Big(1); // Initial guess.
for (var i = 0; i < prec; i++) {
r = (ONE.div(n)).times(r.times(n-1).plus(x.div(r.pow(n-1))));
}
if (negate) r['s'] = -1;
return r;
};
It does not even get obvious results correct like the 4th root of 81 = 3, instead it gets 3.00000000xxx
Newton's method only gives an approximation for the root, so 3.0000xxx should be expected. If you know that the answer should be an integer, you can round r down (Newton's method overestimates the root) and check that r^n=x.
You can use big-numbers library to solve your problem. They support sqrt, pow, exp and many other features.
The pow method accept positive, negative, integer and floating point numbers:
var bn = new BigNumber();
var value = bn.of('81');
var xRoot = value.pow(0.25);
console.log('Result: ' + bn.format(xRoot));
You can use Basenumber.js to perform nth root. Documentation here.
E.g.
// Set precision decimals required
Base.setDecimals(25);
let x = Base("1e+10");
console.log(x.root(10).toString());
<script src='https://cdn.jsdelivr.net/gh/AlexSp3/Basenumber.js#main/BaseNumber.min.js'></script>

Categories

Resources