问题
My question:
How can I create a list of random numbers with a given mean and standard deviation (sd) in Javascript?
Example:
I want to create a list with 5 random numbers in a range between 1 to 10. The resulting mean should be 5 and the standard deviation should be 2.
What I've done so far:
My idea was (http://jsfiddle.net/QASDG/3/):
- Make a function (named "createData") which creates 5 random numbers between 1 and 10 and push them into an "array"
- This function should also calculate the mean (and the sd) of those 5 numbers.
- With a "do-while"-loop: Do the above function as long as the "average becomes 5" (and "sd becomes 2"). But when I call the do-while Loop, the browser crashes of course because there are a lot of cases when the average is != 5 (and the sd != 2).
Note: I haven't add the SD yet, since the code isn't very elegant.
I've found another script from this site which stated: "The goal of this code is to generate a collection filled with 5 normally distributed random numbers with a mean of 1.0 and a standard deviation of 0.5." http://rosettacode.org/wiki/Random_numbers#JavaScript. I've tried to adjust it according to my needs by adding "Math.floor" and changed the condition in the "for"-loop (i < 5).
function randomNormal() {
return Math.floor(Math.cos(2 * Math.PI * Math.random()) * Math.sqrt(-2 * Math.log(Math.random())))
}
var a = []
for (var i=0; i < 5; i++){
a[i] = randomNormal() / 2 + 1
}
How I want to modify my code:
I'm not quite sure whether I've understood the mathematical part of this code. According to the webpage it will create a normal distribution (which is great but not necessary). So what I need in addition is:
- Where can I change the given mean and sd (e.g. mean = 5, sd = 2) in order to create random numbers (which fulfill those properties).
- How do I implement the range between 1 and 10? (Maybe I could use something like: Math.floor(Math.random()*10)+1)
Thanks a lot!
回答1:
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 = oldSD * (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;
}
Limitations
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.
来源:https://stackoverflow.com/questions/22619719/javascript-generate-random-numbers-with-fixed-mean-and-standard-deviation