#mysql #sql #random
Вопрос:
У меня есть следующая таблица под названием original_table
:
name height age
personA 180 21
personB 190 37
personC 168 27
personD 182 56
...
Моя цель состоит в том, чтобы создать две случайные выборки размером 100 из original_table
таких, чтобы средний возраст обычно распределялся около 25 лет, а средний рост был близок к 175. В принципе, человек в возрасте 25 лет и ростом 175 имеет самые высокие шансы попасть в таблицы, но не гарантируется.
Комментарии:
1. Нормальное распределение характеризуется двумя параметрами: средним значением и стандартным отклонением. В вашем вопросе нет никакого объяснения того, какое стандартное отклонение вы хотите. Если вам просто нужно симметричное распределение, где среднее значение является наиболее распространенным значением, существует бесконечное число распределений и простых способов генерирования таких данных в MySQL.
Ответ №1:
Хитрость заключается в том, чтобы найти нормальную функцию распределения из других языков, а затем преобразовать ее в синтаксис mysql. Например, преобразуйте следующий код java в mysql
//java.util.Random
synchronized public double nextGaussian() {
// See Knuth, ACP, Section 3.4.1 Algorithm C.
if (haveNextNextGaussian) {
haveNextNextGaussian = false;
return nextNextGaussian;
} else {
double v1, v2, s;
do {
v1 = 2 * nextDouble() - 1; // between -1 and 1
v2 = 2 * nextDouble() - 1; // between -1 and 1
s = v1 * v1 v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
}
with recursive t0(v1, v2, s, num1, num2, rn) as (
select @v1:= rand() * 2 - 1,
@v2:= rand() * 2 - 1,
@s:= @v1*@v1 @v2*@v2,
sqrt(-2 * log(@s) / (@s)) * @v1,
sqrt(-2 * log(@s) / (@s)) * @v2,
@rn:=case when @s < 1 and @s > 0 then 1 else 0 end
union all
select @v1:= rand() * 2 - 1,
@v2:= rand() * 2 - 1,
@s:= @v1*@v1 @v2*@v2,
sqrt(-2 * log(@s) / (@s)) * @v1,
sqrt(-2 * log(@s) / (@s)) * @v2,
@rn:=case when @s < 1 and @s > 0 then 1 else 0 end @rn
from t0
where @rn < 100
)
select 175 t1.num1 * 10,
175 t1.num2 * 10,
25 t1.num1 * 8,
25 t1.num2 * 8
from t0 t1
where t1.num1 is not null
order by t1.num1
;