My question:
How can I create a list of random numbers with a given mean and standard deviation (sd) in Javascript?
Example:
How can I create a list of random numbers with a given mean and standard deviation (sd) in JavaScript?
This appears to be a question about randomly creating a list of numbers that has an exactly specified mean and an exactly specified standard deviation (and not a question about drawing random numbers from a specific probability distribution with a given mean and sd).
A straightforward solution is to draw a list of random numbers, then to shift and scale this list to have the desired mean and sd, as described in this answer from stats.stackexchange.
Say, we generate the following 5 random numbers between 1 and 10:
4.527991433628388
6.3254986488276055
5.123502737960912
7.3331068522336125
9.069573681037484
This list has a mean of 6.475934670737601 and sd of 1.8102412442104023.
Then, we transform each number in the list like this:
newNum = newSD * (oldNum - oldMean) / oldSD + newMean
By setting the new mean to 5 and new sd to 2, we get the following transformed list:
2.847863379160965
4.83379450402964
3.505799227476338
5.947025358346529
7.865517530986525
Computing the mean and sd of this list confirms that they are indeed 5 and 2.
Below is code demonstrating this approach in JavaScript:
// create a list of 5 random numbers between 1 and 10
var list = randomList(5, 1, 10);
// transform the list to have an exact mean of 5 and sd of 2
var newList = forceDescriptives(list, 5, 2);
// display the transformed list and descriptive statistics (mean and sd)
console.log('Transformed random list', newList, descriptives(newList));
// display the original list and descriptive statistics (mean and sd)
console.log('Original random list', list, descriptives(list));
/* demo functions */
function randomList(n, a, b) {
// create a list of n numbers between a and b
var list = [],
i;
for (i = 0; i < n; i++) {
list[i] = Math.random() * (b - a) + a;
}
return list;
}
function descriptives(list) {
// compute mean, sd and the interval range: [min, max]
var mean,
sd,
i,
len = list.length,
sum,
a = Infinity,
b = -a;
for (sum = i = 0; i < len; i++) {
sum += list[i];
a = Math.min(a, list[i]);
b = Math.max(b, list[i]);
}
mean = sum / len;
for (sum = i = 0; i < len; i++) {
sum += (list[i] - mean) * (list[i] - mean);
}
sd = Math.sqrt(sum / (len - 1));
return {
mean: mean,
sd: sd,
range: [a, b]
};
}
function forceDescriptives(list, mean, sd) {
// transfom a list to have an exact mean and sd
var oldDescriptives = descriptives(list),
oldMean = oldDescriptives.mean,
oldSD = oldDescriptives.sd,
newList = [],
len = list.length,
i;
for (i = 0; i < len; i++) {
newList[i] = sd * (list[i] - oldMean) / oldSD + mean;
}
return newList;
}
Note that, due to precision limits in floating-point arithmetic, the demo sometimes computes the exact mean and sd to deviate slightly (like an sd of 2.0000000000000004 instead of 2). Also note that, depending on the desired mean and sd, it may not be possible to generate a list of numbers within a desired range, as described in this answer on math.stackexchange. This means that the transformed list could be in a very different range than the original list. Also note that it is likely not possible to generate lists of random integers from a given range with a given integer mean and integer sd.