Подмножество таблицы таким образом, чтобы выборки обычно распределялись вокруг значения в столбце

#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
;