Вопрос

мне в принципе нужен ответ на этот вопрос SO, который обеспечивает степенное распределение, переведенный для меня на T-SQL.

Я хочу извлечь фамилию по одной из перепись предоставила таблицу имен.Я хочу получить примерно такое же распределение, как и в популяции.В таблице 88 799 имен, ранжированных по частоте.«Смит» занимает 1-й ранг с частотой 1,006%, «Альдеринк» — 88 799-го ранга с частотой 1,7 x 10^-6.«Сандерс» занимает 75 место с частотой 0,100%.

Кривая вообще не обязательно должна точно совпадать.Просто дайте мне примерно 1% "Смит" и примерно 1 на миллион "Алдеринк"

Вот что у меня есть на данный момент.

SELECT [LastName]
FROM [LastNames] as LN
WHERE LN.[Rank] = ROUND(88799 * RAND(), 0)

Но это, конечно, дает равномерное распределение.

Обещаю, что к тому времени, когда мне ответит более умный человек, я все еще буду пытаться разобраться в этом сам.

Это было полезно?

Решение

Зачем соглашаться на степенное распределение, если можно извлечь данные из фактического распределения?

Я предлагаю вам изменить таблицу LastNames, включив в нее числовой столбец, который будет содержать числовое значение, представляющее фактическое количество лиц с более распространенным именем.Вероятно, вам понадобится число в меньшем, но пропорциональном масштабе, скажем, 10 000 на каждый процент представительства.

Тогда список будет выглядеть примерно так:
(кроме трех имен, упомянутых в вопросе, я предполагаю, что это Уайт, Джонсон и др.)

Smith          0   
White     10,060
Johnson   19,123
Williams  28,456
...
Sanders  200,987
..
Alderink 999,997

И выбор имени будет

SELECT TOP 1 [LastName]
FROM [LastNames] as LN
WHERE LN.[number_described_above] < ROUND(100000 * RAND(), 0)
ORDER BY [number_described_above] DESC

Это выбор первого имени, число которого не превышает случайное число [равномерное распределение].Обратите внимание, как запрос использует меньше, чем и заказ в описание- окончание заказа;это будет гарантией того, что будет выбрана самая первая запись (Смит).Альтернативой было бы начать серию со Смита с 10 060, а не с нуля, и отбросить случайные розыгрыши, меньшие этого значения.

Помимо упомянутого выше вопроса об управлении границами (начиная с нуля, а не с 10 060), это решение, наряду с двумя другими ответами на данный момент, такое же, как и решение, предложенное в Дмкиответ на вопрос, указанный в этом вопросе.По сути, идея состоит в том, чтобы использовать CDF (Кумулятивная функция распределения).


Редактировать:
Если вы настаиваете на использовании математическая функция, а не фактическое распределение, следующее должно предоставить степенную функцию, которая каким-то образом передавала бы форму «длинного хвоста» реального распределения.Возможно, вы захотите настроить значение @PwrCoef (которое, кстати, не обязательно должно быть целым числом), по существу, чем больше коэффициент, тем больше смещена к началу списка функция.

DECLARE @PwrCoef INT
SET @PwrCoef = 2
SELECT 88799 - ROUND(POWER(POWER(88799.0, @PwrCoef) * RAND(), 1.0/@PwrCoef), 0)

Примечания:
- дополнительные «.0» в приведенной выше функции важны для того, чтобы заставить SQL выполнять операции с плавающей точкой, а не с целыми числами.
- причина, по которой мы вычитаем вычисление мощности из 88799, заключается в том, что распределение вычислений таково: чем ближе число к концу нашей шкалы, тем больше вероятность, что оно будет нарисовано.Список фамилий сортируется в обратном порядке (скорее всего, сначала имена), нам нужно это вычитание.

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

SELECT [LastName]
FROM [LastNames] as LN
WHERE LN.[Rank]
     = 88799 - ROUND(POWER(POWER(88799.0, 3) * RAND(), 1.0/3), 0)

Какой запрос из вопроса, кроме последней строки.

Повторное редактирование:
Если посмотреть на фактическое распределение, как видно из данных переписи, кривая чрезвычайно крутая и потребует очень большой коэффициент мощности, что, в свою очередь, может привести к переполнению и/или экстремальным ошибкам округления. в наивной формуле, показанной выше.
Более разумным подходом может быть работа на нескольких уровнях, т.е.выполнить одинаковое количество розыгрышей в каждом из, скажем, трёх третей (или четырёх четвертей, или...) совокупного распределения;в каждом из этих списков частей мы будем рисовать, используя степенную функцию, возможно, с одним и тем же коэффициентом, но с разными диапазонами.
Например
Если предположить третьи, список делится следующим образом:

  • Первая треть = 425 имен, от Смита до Альварадо.
  • Вторая треть = 6277 имен, от до Гейнера
  • Последняя треть = 82 097 имен, от Фрисби до конца.

Если бы нам потребовалось, скажем, 1000 имен, мы бы взяли 334 из верхней трети списка, 333 из второй трети и 333 из последней трети.
Для каждой трети мы бы использовали аналогичную формулу, возможно, с большим коэффициентом мощности для первой трети (мы действительно заинтересованы в том, чтобы отдать предпочтение более ранним именам в списке, и также там, где относительные частоты более статистически значимы).Три запроса выбора могут выглядеть следующим образом:

-- Random Drawing of a single Name in top third
--   Power Coef = 12
SELECT [LastName]
FROM [LastNames] as LN
WHERE LN.[Rank]
     =  425 - ROUND(POWER(POWER(425.0, 12) * RAND(), 1.0/12), 0)

-- Second third; Power Coef = 7
...
WHERE LN.[Rank]
     =  (425 + 6277) - ROUND(POWER(POWER(6277.0, 7) * RAND(), 1.0/7), 0)

-- Bottom third; Power Coef = 4
...
WHERE LN.[Rank]
     =  (425 + 6277 + 82097) - ROUND(POWER(POWER(82097.0, 4) * RAND(), 1.0/4), 0)

Другие советы

Вместо сохранения PDF-файла в качестве ранга сохраните CDF (сумму всех частот до этого имени, начиная с Альдекирка).

Затем измените свой выбор, чтобы получить первый LN с рангом, превышающим результат вашей формулы.

Я прочитал вопрос так: «Мне нужно получить поток имен, который будет отражать частоту фамилий из переписи населения США 1990 года».

Возможно, я прочитал этот вопрос немного иначе, чем другие предложения, и хотя ответ был принят, и это очень подробный ответ, я поделюсь своим опытом работы с фамилиями переписи населения.

Я скачал те же данные из переписи 1990 года.Моя цель состояла в том, чтобы создать большое количество имен для отправки на поисковое тестирование во время тестирования производительности приложения для медицинских записей.Фамилии и процент частоты я вставил в таблицу.Я добавил столбец и заполнил его целым числом, которое было произведением «общее количество требуемых имен * частота».Данные о частоте переписи населения не давали в сумме ровно 100%, поэтому мое общее количество имен также было немного меньше требуемого.Мне удалось исправить число, выбирая случайные имена из списка и увеличивая их количество до тех пор, пока я не получил точно необходимое число, случайно добавленное количество никогда не превышало 0,05% от общего числа в 10 миллионов.

Я сгенерировал 10 миллионов случайных чисел в диапазоне от 1 до 88799.Для каждого случайного числа я выбирал это имя из списка и уменьшал счетчик этого имени.Мой подход заключался в том, чтобы имитировать раздачу колоды карт, за исключением того, что в моей колоде было гораздо больше разных карт и разное количество каждой карты.

Сохраняете ли вы реальные частоты вместе с рангами?

Преобразование алгебры из принятого ответа в MySQL не составит труда, если вы знаете, какие значения использовать для n. y будет то, что у вас есть сейчас ROUND(88799 * RAND(), 0) и x0,x1 = 1,88799 Я так думаю, хотя могу неправильно это понять.Единственный нестандартный математический оператор, задействованный с точки зрения T-SQL, — это ^ что просто POWER(x,y) == x^y.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top