Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Фунционал randome как в AdRotator, случайный выбор на основе веса значения 
V
    Опции темы
dazy
Дата 12.5.2007, 18:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 15.9.2006

Репутация: 1
Всего: 8



Подскажите, как реализовать алгоритм случайного выбора из массива на основании веса каждого эл-та.
Поясняю, есть массив: строка(string), - вес(int). Вес в данном случае это относительное число которое устанавливает частоту выбора строки соответсвующей весу. Т.е. строка с весом 20 должна выбираться в 2 раза чаще чем строка с весом 10.

Схожий принцип реализует AdRotator из ASP.Net, там вес записываетя в impressions, на основании которого показываются банеры.

Ну а мне нужно на вход подать массив, на выходе получить строку. 

Подскажите как реализовать, или где копать что ли? Буду признателен за пример.
PM MAIL   Вверх
tol05
Дата 12.5.2007, 19:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



сделай например 
struct S
{
string str;
int w;

public S(string s)
{
str = s;
w = 0;
}

public int W
{
get
{
return w;
}
}

public string GetString()
{
w++;
return str;
}
}

в проге - массив 
S[] strings = new S[100];
for(int i = 0; i<strings.Length; i++)
{
strings[i] = new S("string " + i.ToString());
}

доступ к строке возможен только через GetString(), при запросе строки ее вес увеличивается.
Ну а потом - цикл по всему массиву S[] и смотришь, у кого  W круче, того и вызывают чаще smile

ну а Random :
поставь 2 потока, поставь 2 порога, например выбрать все с весом не меньше чем 50 в один массив, остальные - в другой
один поток с таймером 10 сек, второй - 30 сек.
тот, что чаще фигачит - пусть с большим весом строки печатает, а медленный - "легковесные" smile
Вот и получится, что весовые строки в три раза чаще вылетают.

Это сообщение отредактировал(а) tol05 - 12.5.2007, 20:09


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
stab
Дата 12.5.2007, 21:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 22
Всего: 48



мне в голову приходит только такое решение, надеюсь верное:

1. отсортировать данные так, чтобы меньшие веса шли в начале.
2. сгруппировать элемменты в новом массиве по значению веса. т.е., грубо говоря, создать массив массивов.
3. сгенерировать случайное значение в диапазоне от 0 до суммы весов всех групп.
4. последовательно перебирая все группы сравнивать вес гурппы с полученным случайным числом.
5. если случайное число больше веса группы, вычесть вес группы из этого числа и перейти к следующей группе.
6. иначе, искомая группа найдена. внутри группы элементы равновероятны, т.е. обычный рандом, как при бросании игральной кости.

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

tol05, что-то какие-то пляски с бубном   smile 


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
Gelis
Дата 12.5.2007, 22:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 145
Регистрация: 26.10.2006
Где: Брест

Репутация: 2
Всего: 4



PM MAIL   Вверх
dazy
Дата 12.5.2007, 23:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 15.9.2006

Репутация: 1
Всего: 8



tol05, Чесно говоря, не совсем въехал про потоки... Принцип понятен, но..... а если у меня 50 строк в массиве, мне 50 потоков создавать?

cully,  Спасибо большое за совет. Честно говоря, интерестно было бы посмотреть на ваш алгоритм без гурппировки в массив, ради интереса. Но  нашел алгоритм по проще: без сортировки, без доп. массива, позволяет использовать в качестве весов одинаковые числа, как раз, то что надо.  

Если кому понадобится, это дело называется: weighted random selection.

Большое всем спасибо.
PM MAIL   Вверх
tol05
Дата 12.5.2007, 23:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



 smile  smile  smile 


Уважаемый cully.
Прежде всего хочу со всей откровенностью заявить, что Ваш пост нисколько меня не оскорбил.  smile smile
Я с Вами согласен, стиль ковбойский.   
Просто я не занимаюсь математическими алгоритмами уже несколько лет, фиксание же разнообразных мелких багов откровенно испортило меня и привило вредные привычки. Может быть, отсюда "танцы с бубнами" и все остальные мои беды.

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

Во-первых, нужно было добиться того, что имеет AdRotator, т.е. хранения веса. Как?
Xml аттрибуты - вещь хорошая, когда она есть. А я не увидел, что вес каждой строки 
где-нибудь хранится. Вот я и предложил объект-элемент (кстати, XmlElement тоже ведь
хранит данные аттрибутов в коллекциях?) - структура. И не более того.

Определение весов строк. Вы раскрыли алгоритм учета весов.
Цитата(cully @  12.5.2007,  21:12 Найти цитируемый пост)
отсортировать данные так, чтобы меньшие веса шли в начале

 А кто и как их будет создавать и модернизировать? 
Моя структура это пытается обеспечить.

Реализация. Да, потоки, как вариант. Но я не настаиваю 

Ну вот, теперь я уверен, что изложил свою мысль полностью.

А впрочем... Может и зря я постился.

Это сообщение отредактировал(а) tol05 - 12.5.2007, 23:55


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
dazy
Дата 12.5.2007, 23:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 15.9.2006

Репутация: 1
Всего: 8



Цитата(tol05 @  13.5.2007,  02:46 Найти цитируемый пост)
Во-первых, нужно было добиться того, что имеет AdRotator, т.е. хранения веса. Как?


Вы не верно меня поняли. Задача была получить функционал AdRotator. Т.е. на основании веса выбирать из списка строку (для AdRotatorа - банер) случайным образом. А как веса хранить, это дело десятое.


Цитата(tol05 @  13.5.2007,  02:46 Найти цитируемый пост)
А я не увидел, что вес каждой строки 
где-нибудь хранится.

Я же написал:
Цитата(dazy @  12.5.2007,  21:09 Найти цитируемый пост)
Поясняю, есть массив: строка(string), - вес(int). 



Цитата(tol05 @  13.5.2007,  02:46 Найти цитируемый пост)
 А кто и как их будет создавать и модернизировать? 

Ну с массивами вроде работать не сложно smile

Цитата(tol05 @  13.5.2007,  02:46 Найти цитируемый пост)
Реализация. Да, потоки, как вариант. Но я не настаиваю 

Честно говоря, в первые увидел решение вероятностной задачи за счет потоков!!!
Как наберу 100 постов - вам +1 за неординарное решение!!!

PM MAIL   Вверх
tol05
Дата 13.5.2007, 00:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



Значит перенапрягся я где-то...
А жаль ...


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
sergejzr
Дата 13.5.2007, 00:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Un salsero
Group Icon


Профиль
Группа: Админ
Сообщений: 13285
Регистрация: 10.2.2004
Где: Германия г .Ганновер

Репутация: нет
Всего: 360



Я делал так:

1)
сумма всех весов -> 100% 
На основании этого вырешиваем проценты для каждого элемента.
создаём массив из 100 элементов, инициализируем его нашими значениями, количество берём процентуальное, вырешанное выше.
Например 30% -> 30 элементов итд. 
Это всё делается один раз.

2)
Сам алгоритм:
Выбираем случайное число из 100, берём элемент из массива по этому индексу.

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


--------------------
PM WWW IM ICQ Skype GTalk Jabber AOL YIM MSN   Вверх
stab
Дата 13.5.2007, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 22
Всего: 48



Цитата(dazy @  13.5.2007,  03:36 Найти цитируемый пост)
Честно говоря, интерестно было бы посмотреть на ваш алгоритм без гурппировки в массив, ради интереса. Но  нашел алгоритм по проще: без сортировки, без доп. массива, позволяет использовать в качестве весов одинаковые числа, как раз, то что надо.  

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

про идею с потоками. очень напоминает байку про программера-индуса, его спросили как узнать какая дата будет завтра, в ответ услышали: надо сделать Sleep(1000 * 60 * 60 * 24), а потом взять текущую дату.


--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
dazy
Дата 14.5.2007, 07:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 15.9.2006

Репутация: 1
Всего: 8



Цитата(cully @  13.5.2007,  19:09 Найти цитируемый пост)
хотя.. если данных много то лучше сортировку сделать, чтобы бинарный поиск использовать для ускорения процеса


Позволю не согласится на счет сортиовки. 

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

PM MAIL   Вверх
stab
Дата 14.5.2007, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Экс. модератор
Сообщений: 1839
Регистрация: 1.1.2003

Репутация: 22
Всего: 48



Цитата(dazy @  14.5.2007,  11:14 Найти цитируемый пост)
Тогда большие числа будут в начале массива, а поскольку вероятность попадания в них выше (по определению), просмотр списка будет обрываться выходом в самом начале. Лишь за редким исключением проходя его весь (конечно все от весов зависит, если все веса примерно равны, то пофиг. но тогда и сотировка не поможет).

идея в бинарном поиске, а не в последовательном просмотре. для этого надо: иметь сортированный массив и, как писал sergejzr, "определить границы отдельных элементов".

Цитата(dazy @  14.5.2007,  11:14 Найти цитируемый пост)
 Но где проводить саму сотрировку? При добавлении в массив? Перед вызовом функции? Есть большие подозрения, что экономия на скорости выполнения агоритма, не окупит затрат процессорного времени на сортировку. 

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

если скорость работы устраивает, оптимизировать нет смысла; как говориться, проблемы надо решать по мере их поступления.



--------------------
6, 6, 6 - the number of the beast.
PM MAIL WWW   Вверх
Gelis
Дата 14.5.2007, 15:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 145
Регистрация: 26.10.2006
Где: Брест

Репутация: 2
Всего: 4



Выскажу свою идею
Цитата(dazy @  12.5.2007,  18:09 Найти цитируемый пост)
 есть массив: строка(string), - вес(int).

Нужно преобразовать в массив строка(string), - вес_относ(double) следующим образом:
определить относительный вес каждого из элементов:
вес_относ()=вес(int)/сумму_весов(int).
Далее составить интервалы частот с.о.:
вес_относ[0]=вес[0]/сумму_весов(int);

вес_относит[i]=вес_относ[i-1]+вес[i]/сумму_весов(int);

получим массиву строк соответсвует отсортированный массив относительных частот.
Далее вызываем Random.NextDouble() который выдает, равномернораспределенную СВ на отрезке 
[0;1]. И бинарным поиском ищем i такое, что вес_относит[i-1]<=Random.NextDouble()<вес_относит[i]

PM MAIL   Вверх
adLucem
Дата 15.5.2007, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 94
Регистрация: 17.4.2007
Где: Украина, Донецк

Репутация: 4
Всего: 5



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

Код

// Общий вес всех элементов.
int bound = 0;
foreach ( int weight in Elements_.Values ) {
    bound += weight;
}
// Случайное число в диапазоне от 0 до общего веса, каждому элементу принадлежит диапазон, равный его весу.
int selected = ( ( new Random ( ) ).Next ( ) % bound );
// Ищем диапазон, в который попало случайное значение.
foreach ( KeyValuePair<string, int> element in Elements_ ) {
    if ( selected < element.Value ) {
        return element.Key;
    } else {
        selected -= element.Value;
    }
}


Элементы хранятся в
Код

Dictionary<string, int> Elements_;


Это сообщение отредактировал(а) adLucem - 15.5.2007, 15:50
PM MAIL ICQ   Вверх
dazy
Дата 17.5.2007, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 344
Регистрация: 15.9.2006

Репутация: 1
Всего: 8



Если кого интересует, вот как эта функция реализована в самом AdRotator

Код

private IDictionary SelectAdFromRecords()
{
    if ((this._adRecs == null) || (this._adRecs.Length == 0))
    {
        return null;
    }
    string keywordFilter = this.KeywordFilter;
    bool flag = string.IsNullOrEmpty(keywordFilter);
    if (!flag)
    {
        keywordFilter = keywordFilter.ToLower(CultureInfo.InvariantCulture);
    }
    int maxValue = 0;
    for (int i = 0; i < this._adRecs.Length; i++)
    {
        if (flag || this.MatchingAd(this._adRecs[i], keywordFilter))
        {
            maxValue += this._adRecs[i].impressions;
        }
    }
    if (maxValue == 0)
    {
        return null;
    }
    int randomNumber = GetRandomNumber(maxValue);
    int num4 = 0;
    int index = -1;
    for (int j = 0; j < this._adRecs.Length; j++)
    {
        if (flag || this.MatchingAd(this._adRecs[j], keywordFilter))
        {
            num4 += this._adRecs[j].impressions;
            if (randomNumber <= num4)
            {
                index = j;
                break;
            }
        }
    }
    return this._adRecs[index].adProperties;
}

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0699 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.