Корректируйтесь объекты оказываются выбранный из списка


s = 'abcdefgh'
for e in (s[i:i+2] for i in range(0,len(s),2)):
  print(e)
10
задан Thad 19 October 2009 в 17:01
поделиться

6 ответов

Здесь мы разработаем генератор случайных чисел, который имеет распределение, которое отдает предпочтение низким значениям. Вы можете использовать его, чтобы отдавать предпочтение элементам в начале списка. Чтобы уменьшить вероятность того, что что-то будет выбрано, переместите этот элемент вниз по списку.У вас есть несколько вариантов, как вы хотите переместить элемент вниз по списку. Давайте сначала рассмотрим преобразование случайной величины.

Применяя следующую функцию к однородной случайной величине от 0 до 1:

index = Int(l*(1-r^(0.5)) # l=length, r=uniform random var between 0 and 1

Вы получаете классное распределение, которое резко снижает шансы на больший индекс

p(0)=0.09751
p(1)=0.09246
p(2)=0.08769
p(3)=0.08211
p(4)=0.07636
p(5)=0.07325
p(6)=0.06772
p(7)=0.06309
p(8)=0.05813
p(9)=0.05274
p(10)=0.04808
p(11)=0.04205
p(12)=0.03691
p(13)=0.03268
p(14)=0.02708
p(15)=0.02292
p(16)=0.01727
p(17)=0.01211
p(18)=0.00736
p(19)=0.00249

Вот распределение для списка размером 2

0.75139
0.24862

Размер 3

0.55699
0.33306
0.10996

Размер 4

0.43916
0.31018
0.18836
0.06231

Теперь давайте обсудим два варианта перемещения элементов вниз по списку. Я протестировал два:

  • ToEnd - переместить последний выбранный элемент в конец списка

  • Sort - сохранить связанный массив с количеством раз, когда каждый элемент был выбран, и отсортировать список от наименьшего к самый избранный.

Я создал симуляцию, чтобы выбрать из списка и проверить стандартное отклонение количества выбранных элементов. Чем меньше стандартное отклонение, тем лучше. Например, 1 симуляция для списка из 10 пунктов, из которых было сделано 50 вариантов, создала распространение:

{"a"=>5, "b"=>5, "c"=>6, "d"=>5, "e"=>4, "f"=>4, "g"=>5, "h"=>5, "i"=>6, "j"=>5}

Стандартное отклонение для этой симуляции было

0.63

. Имея возможность запустить симуляцию, я затем вычислил некоторую мета-статистику, запустив моделирование 500 раз и обеспечение среднего стандартного отклонения для каждого метода: ToEnd и Sort. Я ожидал, что стандартное отклонение будет высоким для небольшого количества выборов, но на самом деле для алгоритма ToEnd стандартное отклонение увеличивалось с количеством выборов. Метод сортировки исправил это.

Testing ["a", "b", "c", "d", "e"]
-------------------------
Picks    ToEnd (StdDev) Sort (StdDev)
5       0.59        0.57
10      0.76        0.68
15      0.93        0.74
20      1.04        0.74
25      1.20        0.73
30      1.28        0.73
35      1.34        0.74
40      1.50        0.75
45      1.53        0.75
45      1.56        0.77
80      2.04        0.79
125     2.52        0.74
180     3.11        0.77
245     3.53        0.79
320     4.05        0.75
405     4.52        0.76
500     5.00        0.78

Вот некоторые результаты тестов для большего набора.

Testing ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
-------------------------
Picks  ToEnd (StdDev)  Sort (StdDev)
10          0.68        0.65
20          0.87        0.77
30          1.04        0.80
40          1.18        0.82
50          1.30        0.85
60          1.43        0.84
70          1.57        0.87
80          1.65        0.88
90          1.73        0.87
90          1.71        0.87
160         2.30        0.89
250         2.83        0.88
360         3.44        0.88
490         3.89        0.88
640         4.54        0.87
810         5.12        0.88
1000        5.66        0.85

Имея хорошую среду тестирования, я не мог устоять перед попыткой другого преобразования случайных чисел.Я предполагал, что если я возьму кубический корень вместо квадратного корня из x, мое стандартное отклонение уменьшится. На самом деле это было так, но я беспокоился, что это уменьшит случайность. Здесь вы можете наблюдать несколько симуляций, когда формула изменена на

index = Int(l*(1-r^(0.33)) # l=length, r=uniform random var between 0 and 1

. Теперь проверьте фактические пикировки. Как я думал,сначала он очень взвешен в начале списка. Если вы хотите сильно взвесить это, вам, вероятно, следует рандомизировать свой список перед тем, как начать.

StdDev = 0.632455532033676
{"a"=>10, "b"=>10, "c"=>11, "d"=>9, "e"=>10}
a d e c b c e b a d b e c a d d e b a e e c c b d a d c b c e b a a d d b e a e a b c b d c a c e c

StdDev = 0.0
{"a"=>10, "b"=>10, "c"=>10, "d"=>10, "e"=>10}
b c d a a d b c b a d e c d e c b e b a e e d c c a b a d a e e b d b a e c c e b a c c d d d a b e

StdDev = 0.632455532033676
{"a"=>9, "b"=>10, "c"=>10, "d"=>10, "e"=>11}
b d a e b c a d c e e b a c a d d c b c e d a e b b a c d c d a e a e e b d c b e a b c b c d d e e

StdDev = 0.0
{"a"=>10, "b"=>10, "c"=>10, "d"=>10, "e"=>10}
a b e d c e a b d c b c c a d b e e b e a d d c e a d b b c c a a a b e d d e c c a b b e a c d e d

StdDev = 0.632455532033676
{"a"=>11, "b"=>10, "c"=>9, "d"=>10, "e"=>10}
b a d c d c a e b e a e b c d b c a a d e e d c d e c b a b b e d c d b c e a a a d b c e b e a d a
8
ответ дан 3 December 2019 в 20:05
поделиться

Используйте взвешенную по сегменту очередь: Вместо использования списка разделите вашу коллекцию на сегменты - каждому сегменту соответствует частота извлечения. По мере выбора элементы перемещаются из сегментов с более высокой частотой в сегменты с меньшей частотой.

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

Алгоритм:

Изначально все элементы начинаются в одной корзине (верхнего уровня).

Когда вы выбираете элемент, переместите его из ведра, в котором он находится, в следующее нижнее ведро. При необходимости создайте сегмент следующего уровня.

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

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

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

Реализация на C # (первый вариант) общей взвешенной очереди с разделением на сегменты:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Utility
{
    public class BucketWeightedQueue<T>
    {
        private int m_MaxFallOff;
        private readonly double m_FallOffRate;
        private readonly List<List<T>> m_Buckets;
        private readonly List<int> m_FallOffFactors;
        private readonly Random m_Rand = new Random();

        public BucketWeightedQueue(IEnumerable<T> items, double fallOffRate )
        {
            if( fallOffRate < 0 ) 
                throw new ArgumentOutOfRangeException("fallOffRate");

            m_MaxFallOff = 1;
            m_FallOffRate = fallOffRate;
            m_Buckets = new List<List<T>> { items.ToList() };
            m_FallOffFactors = new List<int> { m_MaxFallOff };
        }

        public T GetRandomItem()
        {
            var bucketIndex = GetRandomBucketIndex();
            var bucket = m_Buckets[bucketIndex];
            var itemIndex = m_Rand.Next( bucket.Count );
            var selectedItem = bucket[itemIndex];

            ReduceItemProbability( bucketIndex, itemIndex );
            return selectedItem;
        }

        private int GetRandomBucketIndex()
        {
            var randFallOffValue = m_Rand.Next( m_MaxFallOff );
            for (int i = 0; i < m_FallOffFactors.Count; i++ )
                if( m_FallOffFactors[i] <= randFallOffValue )
                    return i;
            return m_FallOffFactors[0];
        }

        private void ReduceItemProbability( int bucketIndex, int itemIndex )
        {
            if( m_FallOffRate <= 0 )
                return; // do nothing if there is no fall off rate...

            var item = m_Buckets[bucketIndex][itemIndex];
            m_Buckets[bucketIndex].RemoveAt( itemIndex );

            if( bucketIndex <= m_Buckets.Count )
            { 
                // create a new bucket...
                m_Buckets.Add( new List<T>() );
                m_MaxFallOff = (int)(m_FallOffFactors[bucketIndex] / m_FallOffRate);
                m_FallOffFactors.Add( m_MaxFallOff );
            }

            var nextBucket = m_Buckets[bucketIndex + 1];
            nextBucket.Add( item );

            if (m_Buckets[bucketIndex].Count == 0) // drop empty buckets
                m_Buckets.RemoveAt( bucketIndex );
        }
    }
}
8
ответ дан 3 December 2019 в 20:05
поделиться

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

По умолчанию весовой коэффициент равен 1, когда вы добавляете элемент, и сохраняете (в «списке») сумма всех весов всех элементов.

Затем, когда вы выбираете элемент случайным образом, вы можете просто выбрать число от 0 до общего веса всех элементов в списке, и пройдите по списку, чтобы найти элемент в этой «позиции» (путем взвешивания). Уменьшите вес этого элемента (это может быть некоторый спад, например: умножьте его вес на 0,8 или 0,5 - у вас будет большой контроль над тем, насколько быстро падает вероятность выбора) и верните его.

Обратной стороной здесь является то, что если у вас много элементов, вы выбираете O (n) (поскольку вам нужно пройтись по списку). Из-за этого я

1
ответ дан 3 December 2019 в 20:05
поделиться

Все зависит от того, как должна изменяться вероятность выбора при выборе данного элемента.

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

Общая концепция кажется связанной с эргодические источники.

DigitalJoe прокомментировал очевидный недостаток этого подхода. Вкратце, Джо отметил, что вероятность предотвращения повторения (не обязательно последовательных повторов, просто «повторения» ) значение ранее нарисованного элемента (значение, найденное во втором списке алгоритма) сильно колеблется в первых нескольких сотнях рисунков. Другой неявный комментарий заключался в том, что после того, как второй список содержит несколько десятков значений, вероятность предотвращения такого дублирования чрезвычайно мала. Оба эти аргумента являются действительными и требуют квалификации.

Это рассуждение соответствует нашему интуитивному пониманию того, как работает второй список: чем больше значений элементов там, тем меньше шансов, что у нас есть «двойная вытяжка», следовательно, чтобы предотвратить повторение. Это правда, но мы сосредоточимся только на втором списке. Необходимо учитывать вероятность получения [из первого списка] ранее увиденного предмета. Мы можем использовать два примера, чтобы понять эту идею, но это, конечно, градиент:

  • Случай «A»: Вероятность получения данного значения элемента относительно мала по сравнению с вероятностью получения чего-либо другого. Комбинированная вероятность того, что этот предмет будет вытягиваться несколько раз в течение первых нескольких розыгрышей, поэтому мала, и вероятность того, что вы это сделаете, а затем выбросите его из-за розыгрыша (ов) в списке два, еще ниже (даже если последняя вероятность может быть высокая из-за небольшого количества элементов во втором списке).
  • Случай «B»: вероятность вытягивания данного предмета высока по сравнению с вероятностью вытягивания других предметов. В этом случае вероятность наличия повторов в первых нескольких розыгрышах высока, и поскольку вероятность предотвращения фактического повтора (с розыгрышем во втором списке) также высока (достоверность для 2-го розыгрыша, вероятность 50% на втором розыгрыше ... шанс 10% на 11 розыгрыше), общая вероятность "наказать" весьма вероятный предмет высока. Однако это не проблема, потому что относительная вероятность рисования элемента из первого списка гарантирует, что будет, статистически, много других возможностей для создания дубликатов, которые не будут так «принудительно» подавляться по мере увеличения количества рисунков. .

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

Что касается вопроса о возможности наличия слишком слабого фильтра повторов, то это тоже становится менее актуальным, поскольку второй список отражает все больше и больше раздача первого списка. Алго 1: Отрисовка без замены из первого списка. Что мы будем использовать копию исходного списка для начала, и каждый раз, когда данный элемент рисуется, мы удаляем его из этого списка, что в целом снижает вероятность того, что то же значение появится снова. К тому времени, когда мы нарисовали все элементы, мы точно воспроизвели распределение исходного списка.
Алгоритм 2: Рисование без замены из списка, в котором исходный список был воспроизведен заданное количество раз . Это похоже на вышеизложенное, но вводит немного больше случайности, т.е. требует большего количества рисунков, чтобы иметь подход распределения рисунков и совпадать с исходным списком.

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

2
ответ дан 3 December 2019 в 20:05
поделиться

Использовать время, прошедшее с момента вставки или последнего выбора элемента, в качестве усиления приоритета ... Установите приоритет каждого элемента = количество времени с момента его вставки или последнего выбора, а затем настройте его шанс быть выбранным путем умножения на этот приоритет.

Как только у вас есть шансы всех элементов, нормализуйте их (отрегулируйте их все одинаковым расчетным соотношением, чтобы получить в сумме 1.000), затем используйте эти значения как их вероятность быть выбранными.

0
ответ дан 3 December 2019 в 20:05
поделиться

общая стратегия выбора взвешенный случайный элемент из списка таков: присвоить каждому элементу вес. нормализовать, чтобы общий вес был 1. (поэтому для начала каждый элемент имеет вес 1 / n). отсортируйте список по весу. теперь выберите случайное число от 0 до 1 и двигайтесь вниз по списку, накапливая итоги, пока не пересечете свое число. например, если ваши веса [0,4, 0,3, 0,2, 0,1] и ваше случайное число 0,63215, ваши первые два шага имеют total = 0,4, total = 0,7, а затем обратите внимание, что 0,7 больше 0,63215, поэтому вы возвращаете второй элемент.

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

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

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

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

0
ответ дан 3 December 2019 в 20:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: