Случайный взвешенный выбор в T-SQL

Для всех книг ML, которые я изучал, W всегда определяется как индекс связности между двумя нейронами, что означает более высокую связь между двумя нейронами, тем сильнее будут передаваться сигналы от обжигающего нейрона до целевого нейрона или Y = w * X, чтобы сохранить биологический характер нейронов, нам нужно сохранить 1> = W> = -1, но в реальной регрессии W будет иметь | W | > = 1, что противоречит тому, как работают нейроны, в результате я предлагаю W = cos (theta), а 1> = | cos (theta) | , и Y = a * X = W * X + b, тогда как a = b + W = b + cos (theta), b - целое число

24
задан ConcernedOfTunbridgeWells 8 October 2008 в 22:18
поделиться

5 ответов

Ответ Дейна включает в себя само присоединение таким образом, который вводит квадратный закон. (n*n/2) строк после объединения, где в таблице n строк.

Что было бы более идеальным, так это возможность только один раз проанализировать таблицу.

DECLARE @id int, @weight_sum int, @weight_point int
DECLARE @table TABLE (id int, weight int)

INSERT INTO @table(id, weight) VALUES(1, 50)
INSERT INTO @table(id, weight) VALUES(2, 25)
INSERT INTO @table(id, weight) VALUES(3, 25)

SELECT @weight_sum = SUM(weight)
FROM @table

SELECT @weight_point = FLOOR(((@weight_sum - 1) * RAND() + 1), 0)

SELECT
    @id = CASE WHEN @weight_point < 0 THEN @id ELSE [table].id END,
    @weight_point = @weight_point - [table].weight
FROM
    @table [table]
ORDER BY
    [table].Weight DESC

Это будет проходить через таблицу, устанавливая @id значение id каждой записи, в то же время уменьшая точку @weight. В конце концов, @weight_point станет отрицательным. Это означает, что SUM всех предыдущих весов больше, чем случайно выбранное целевое значение. Это та запись, которую мы хотим, поэтому с этого момента мы устанавливаем @id себе (игнорируя любые идентификаторы в таблице).

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

DECLARE @id int, @weight_sum int, @weight_point int, @next_weight int, @row_count int
DECLARE @table TABLE (id int, weight int)

INSERT INTO @table(id, weight) VALUES(1, 50)
INSERT INTO @table(id, weight) VALUES(2, 25)
INSERT INTO @table(id, weight) VALUES(3, 25)

SELECT @weight_sum = SUM(weight)
FROM @table

SELECT @weight_point = ROUND(((@weight_sum - 1) * RAND() + 1), 0)

SELECT @next_weight = MAX(weight) FROM @table
SELECT @row_count   = COUNT(*)    FROM @table
SET @weight_point = @weight_point - (@next_weight * @row_count)

WHILE (@weight_point > 0)
BEGIN
    SELECT @next_weight = MAX(weight) FROM @table WHERE weight < @next_weight
    SELECT @row_count   = COUNT(*)    FROM @table WHERE weight = @next_weight
    SET @weight_point = @weight_point - (@next_weight * @row_count)
END

-- # Once the @weight_point is less than 0, we know that the randomly chosen record
-- # is in the group of records WHERE [table].weight = @next_weight

SELECT @row_count = FLOOR(((@row_count - 1) * RAND() + 1), 0)

SELECT
    @id = CASE WHEN @row_count < 0 THEN @id ELSE [table].id END,
    @row_count = @row_count - 1
FROM
    @table [table]
WHERE
    [table].weight = @next_weight
ORDER BY
    [table].Weight DESC
15
ответ дан Dawid Ferenczy Rogožan 29 November 2019 в 00:10
поделиться

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

DECLARE @id int, @weight_sum int, @weight_point int
DECLARE @table TABLE (id int, weight int)

INSERT INTO @table(id, weight) VALUES(1, 50)
INSERT INTO @table(id, weight) VALUES(2, 25)
INSERT INTO @table(id, weight) VALUES(3, 25)

SELECT @weight_sum = SUM(weight)
FROM @table

SELECT @weight_point = ROUND(((@weight_sum - 1) * RAND() + 1), 0)

SELECT TOP 1 @id = t1.id
FROM @table t1, @table t2
WHERE t1.id >= t2.id
GROUP BY t1.id
HAVING SUM(t2.weight) >= @weight_point
ORDER BY t1.id

SELECT @id
7
ответ дан Dane 29 November 2019 в 00:10
поделиться

«постепенно переносить накопительную [sic] весовую сумму» часть дорогая, если у вас много записей. Если у вас уже есть широкий диапазон баллов / весов (т. Е. Диапазон достаточно широк, чтобы большинство весов записей были уникальными. 1-5 звезд, вероятно, не снизили бы его), вы можете сделать что-то подобное, чтобы выбрать значение веса. , Я использую VB.Net здесь, чтобы продемонстрировать, но это легко можно сделать и на чистом языке Sql:

Function PickScore()
    'Assume we have a database wrapper class instance called SQL and seeded a PRNG already
    'Get count of scores in database
    Dim ScoreCount As Double = SQL.ExecuteScalar("SELECT COUNT(score) FROM [MyTable]")
    ' You could also approximate this with just the number of records in the table, which might be faster.

    'Random number between 0 and 1 with ScoreCount possible values
    Dim rand As Double = Random.GetNext(ScoreCount) / ScoreCount

    'Use the equation y = 1 - x^3 to skew results in favor of higher scores
    ' For x between 0 and 1, y is also between 0 and 1 with a strong bias towards 1
    rand = 1 - (rand * rand * rand)

    'Now we need to map the (0,1] vector to [1,Maxscore].
    'Just find MaxScore and mutliply by rand
    Dim MaxScore As UInteger = SQL.ExecuteScalar("SELECT MAX(Score) FROM Songs")
    Return MaxScore * rand
End Function

Запустите это и выберите запись с наибольшим счетом, меньшим, чем возвращаемый вес. Если этот результат набрал более одной записи, выберите его наугад. Преимущества здесь в том, что вам не нужно поддерживать какие-либо суммы, и вы можете настроить уравнение вероятности, которое будет соответствовать вашим вкусам. Но опять же, это лучше всего работает при большем распределении баллов.

3
ответ дан Joel Coehoorn 29 November 2019 в 00:10
поделиться

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

В базе данных последующие значения после вставки должны быть обновлены. Если относительная частота обновлений и размер набора данных не делают затраты на выполнение этого запретительного действия, это означает, что соответствующее значение может быть получено из одного запроса s-argable (предикат, который может быть разрешен поиском по индексу) .

2
ответ дан ConcernedOfTunbridgeWells 29 November 2019 в 00:10
поделиться

Если вам нужно получить группу сэмплов (скажем, вы хотите сэмплировать 50 строк из набора из 5M строк), где у каждой строки есть столбец с именем Weight, который является int и где большие значения означают Вы можете использовать эту функцию:

SELECT * 
FROM 
(
    SELECT TOP 50 RowData, Weight 
    FROM MyTable 
    ORDER BY POWER(RAND(CAST(NEWID() AS VARBINARY)), (1.0/Weight)) DESC
) X 
ORDER BY Weight DESC

Ключ здесь использует функцию POWER (), как показано на рисунке здесь

Ссылка на выбор случайная функция здесь и здесь

В качестве альтернативы вы можете использовать:

1.0 * ABS(CAST(CHECKSUM(NEWID()) AS bigint)) / CAST(0x7FFFFFFF AS INT) 

Вы приводите контрольную сумму как BIGINT вместо INT из-за этой проблемы:

Поскольку контрольная сумма возвращает целое число, а диапазон целого числа составляет от -2 ^ 31 (-2 147 483 648) до 2 ^ 31-1 (2 147 483 647) функция abs () может возвращать ошибку переполнения, если результат равен точно 2 147 483 648! Шансы, очевидно, очень малы, около 1 на 4 миллиарда, однако мы каждый день запускали их по таблице строк ~ 1,8 млрд, так что это происходило примерно раз в неделю! Исправление - привести контрольную сумму к bigint до пресса.

0
ответ дан Shiroy 29 November 2019 в 00:10
поделиться