Имя: Пароль:
IT
 
Случайная выборка
0 Asmody
 
15.03.13
09:12
простая задача, не могу придумать эффективного решения.
есть ТЗ, одна из колонок - Вероятность, от 0до 100. Нужно придумать функцию, которая возвращает строку ТЗ с вероятностью Вероятность/Итог(Вероятность). При этом считаем, что функция Случайное() возвращает случайное число от 0 до 100
1 mikecool
 
15.03.13
09:13
не понял, предлагаешь придумать генератор случайного числа?
2 1C-band
 
15.03.13
09:13
ГенераторСлучайныхЧисел (RandomNumberGenerator)
СлучайноеЧисло (RandomNumber)
Синтаксис:

СлучайноеЧисло(<НижнийДиапазон>, <ВерхнийДиапазон>)
Параметры:

<НижнийДиапазон> (необязательный)

Тип: Число.
Нижний диапазон. Задается целым числом и не может быть меньше 0.
Значение по умолчанию: 0
<ВерхнийДиапазон> (необязательный)

Тип: Число.
Верхний диапазон. Задается целым числом и не может быть больше 4294967295 (2^32 - 1), а также меньше значения параметра <НижнийДиапазон>.
Значение по умолчанию: 4294967295
Возвращаемое значение:

Тип: Число.

Описание:

Возвращает случайное целое число в заданном диапазоне. Нижний диапазон не может быть меньше 0, а верхний диапазон не может быть больше 2^32 - 1.

Доступность:

Тонкий клиент, сервер, толстый клиент, внешнее соединение.
Пример:

ГСЧ = Новый ГенераторСлучайныхЧисел(255);
ГСЧ.СлучайноеЧисло(0, 10000);
3 Asmody
 
15.03.13
09:14
(1) (2) спасибо, вы задачу не читали
4 mikecool
 
15.03.13
09:15
или нужно найти строку, у которой будет
Вер/Итог(Вер) = Случайное() ?
5 1C-band
 
15.03.13
09:15
(3) Итог(Вероятность) всегда будет = 1. Или я не догоняю?
6 Asmody
 
15.03.13
09:15
(4) мне нужна строка ТЗ
7 mikecool
 
15.03.13
09:15
(3) а ты сам прочитай ее, них не понятно
8 Asmody
 
15.03.13
09:16
(5) колонка Вероятность от 0 до 100
9 dk
 
15.03.13
09:16
(0) уже пятницу отмечаешь что ли? ))
если будет 3 строки с вероятностью
стр 1 - 30
стр 2 - 60
стр 3 - 90
----
какую выборку ты думаешь получить?
10 Wobland
 
15.03.13
09:16
Функция ПолучитьСлучайнуюНоменклатуру(Исключаемые=0) Экспорт
   ГСЧ=Новый ГенераторСлучайныхЧисел;
   Запрос=Новый Запрос;
   Запрос.Текст=
   "ВЫБРАТЬ
   |    Номенклатура.Ссылка
   |ИЗ
   |    Справочник.Номенклатура КАК Номенклатура
   |ГДЕ
   |    (НЕ Номенклатура.Ссылка В (&Исключение) ИЛИ &Исключение=0)
   |    И НЕ Номенклатура.ПометкаУдаления";
   Запрос.УстановитьПараметр("Исключение", Исключаемые);
   Результат=Запрос.Выполнить().Выгрузить();
   
   Если Результат.Количество()=0 Тогда
       Возврат Справочники.Номенклатура.ПустаяСсылка();
   Иначе
       Возврат Результат[ГСЧ.СлучайноеЧисло(0, Результат.Количество()-1)].Ссылка;
   КонецЕсли;
КонецФункции
11 НафНаф
 
15.03.13
09:16
вероятность не может быть от 0 до 100, только до 1
12 Asmody
 
15.03.13
09:22
пример:

+---+----+
!  1 !  20 !
+---+----+
!  2 !  30 !
+---+----+
!  3 !   10  !
+---+----+


в 20 случаев из 60 должна выпасть строка 1, в 30 из 60 - строка 2, в 10 из 60 -  строка 3. естественно, речь о статистическом количестве.
(извините за качество, пишу с утюга)
13 Asmody
 
15.03.13
09:24
(11) Вероятность/Итог(Вероятность) всегда меньше 1, не так ли?
14 Гефест
 
15.03.13
09:24
Размножь строки таблицы так, чтобы их количество было пропорционально вероятности, потом ткни случайно в строку
15 Wobland
 
15.03.13
09:25
(13) или равно
16 Karavanych
 
15.03.13
09:25
Функция возвращаемСтроку()
   ТЗ=Новый ТаблицаЗначений;
   МаксВероятность;
   НомерВозвращаемойСтроки;
   НПП=0;
   Для каждого СтрокаТЗ из ТЗ цикл
       НПП=НПП+1;
       Если ТЗ.Вероятность*Случайное()>МаксВероятность тогда
           НомерВозвращаемойСтроки=НПП;
           МаксВероятность=ТЗ.Вероятность*Случайное();
       КонецЕсли;
   КонецЦикла;
   
   возврат Тз.Получить(НомерВозвращаемойСтроки);
КонецФункции
17 Asmody
 
15.03.13
09:26
(14) это была первая идея. думал что-то поэффективнее найти
18 Karavanych
 
15.03.13
09:29
(17) ИтогВероятности=ТЗ.Итог("Вероятность");
возьми случайное число от 0 до ИтогВероятности;
Распредели полученное как остаток построчно, где закончилось - ту строку возвращай.

P.S. и эта... я перевел 65$m.
19 Asmody
 
15.03.13
09:30
(18) сейчас до офиса доберусь, все сделаю
20 Lama12
 
15.03.13
09:30
(12) Если не ошибаюсь, это называется метод монте-карло.
Верно понял задачу?
21 dk
 
15.03.13
09:31
можно решить через вспомогательную таблицу, но мутно конечно
1. считаем вероятность для каждой строки как
КоличествоПопаданий = ОКР(ТЗ.Вероятность/ТЗ.Итог(Вероятность)*1000)
2. Создаем вспомогательную ТЗ2 с Колонкой "НомерСтрокиИсхТЗ"
3. Записываем в ТЗ2 номер строки из ТЗ столько раз, сколько посчитали в КоличествоПопаданий
4. Надо перемешать ТЗ2 в случайном порядке (еще 1 цикл + сортировка)
5. Строим выборку по ТЗ2 - тупо по очереди считываем и дергаем данные из ТЗ по номеру строки
22 Karavanych
 
15.03.13
09:32
(19) и эта... про Итог по вероятности отличная идея кстати, не пропусти. эффективнее метода нет.
23 Asmody
 
15.03.13
09:33
пока в голове крутится вариант сделать еще колонку, в котором посчитать вероятности накопленным итогом, потом уже элементарный поиск
24 HeroShima
 
15.03.13
09:33
Каждой вероятности выделить диапазон значений Случайное().
25 dk
 
15.03.13
09:36
(14) быстрый и простой вариант, но распределение может не совпадать с заданным
(21) гарантированное заданное распределение
26 Xapac_2
 
15.03.13
09:36
(23)может расскажете полное условие задачи, чтобы люди не гадали?
я(0) понял
строка = ТабличнаяЧасть[Рандом(КоличествоСтрок)]
27 shpioleg
 
15.03.13
09:36
Тоже был бы интересен оригинальный алгоритм. Пока сделано аналогично как в (14), но и вероятности у меня поменьше (от 1 до 10), т.к. что массив для выборки случайного индекса получается небольшой.
28 Asmody
 
15.03.13
09:37
(20) ну да, похоже. но я бы сказал, что это реализация дискретной случайной величины с заданной гистограммой
29 Лефмихалыч
 
15.03.13
09:37
(0) что на вход этой функции подается?
что означает формулировка "возвращает строку ТЗ с вероятностью Вероятность/Итог(Вероятность)"?
30 Karavanych
 
15.03.13
09:38
вот смотри пример

Вероятность Данные
10          ололо
20          олололо
5           ололол
15          олололо

Итог(50);
Ты берешь случайно от 0 до 50, и соответственно начинаешь раскидывать остаток.
например рендом дал 34.

ты берешь построчно распределяешь полученное
10 - 10, закрлось
20 - 20 закрылось
5 - 4, не закрылось - возвращаем эту строку...

все у тебя 100% верное распределение получается, используя рендом 1 раз не дробя строки.
31 Лефмихалыч
 
15.03.13
09:43
(12) а, вон оно чо. Ну сделай соответствие из 60 элементов. Индекс соответствия - число от 0 до 60. Значение - индекс строки. Заполняй при обходе исходной таблицы - первые 20 значений = 1, следующие 30 = 2, остальные 10 = 3.

Далее просто генери случайное число от 1 до 60 и по этому числу получай из соответствия номер строки.

Главное, чтобы генератор не возврщал дублей, а это легко решается
32 Asmody
 
15.03.13
09:43
(30) да, это вариант. попробуем
33 НафНаф
 
15.03.13
09:45
(13) сама по себе вероятность - величина в интервале от 0 до 1
34 HeroShima
 
15.03.13
09:46
(30) и если отсортировать по убыванию вероятности, будет работать быстрее
35 HeroShima
 
15.03.13
09:47
(33) а вероятность * 100% уже не вероятность? )
36 Asmody
 
15.03.13
09:51
задачу тут кто-то просил целиком, озвучиваю:
задумали наши продажники акцию: при сумме заказа от...  подарок покупателю. но чтоб все было по-честному, подарок сам должен в заказ вставляться вот с такой вероятностью.
вот, собственно, и все
37 Asmody
 
15.03.13
09:54
(36)+ ну т. е. подарков несколько видов, похуже, получше. ну и получается, что на один телевизор 5000 ручек и т. д.
38 Karavanych
 
15.03.13
09:54
(36) вероятность определяет какой именно подарок ?
39 Ivan Bezdomnyi
 
15.03.13
09:57
Мой вариант.
Вспомогательную колонку "Предел"
если смотреть на вариант (12)
+---+----+
! 1 ! 20 ! 20
+---+----+
! 2 ! 30 ! 50
+---+----+
! 3 ! 10 ! 60
+---+----+
и т.д. следующее = сумме предыдущих по колонке "Вероятность".
В итоге получим случайное число от 0 до (Итог по колонке "Вероятность") и найдем соответствующую строку.
Т.е. если выпало 11 - первая строка
например 35 - вторая строка
если 56 - третья
40 Лефмихалыч
 
15.03.13
10:01
(36) каша какая-то. так от чего зависит, какой подарок должен в накладную подставляться? Чем больше сумма, тем лучше подарок или как?
41 Xapac_2
 
15.03.13
10:02
(40)думаю вероятность сами манегеры выставляют.
42 ptiz
 
15.03.13
10:03
К таблице из (12) добавляем пару колонок (первая- значение из пред.строки +1, вторая - накопительный итог):
+---+----+  ----+----+
! 1 ! 20 !    1 ! 20 !
+---+----+  ----+----+
! 2 ! 30 !   21 ! 50 !
+---+----+  ----+----+
! 3 ! 10 !   51 ! 60 !
+---+----+  ----+----+

Генерируем сл.число от 1 до 60 и смотрим, в какой диапазон оно попадает (с конца таблицы проходим).
И такую строку берем.
43 ptiz
 
15.03.13
10:04
+(42) про "с конца таблицы" - не читать :)
Собственно, в (39) то же самое
44 Лефмихалыч
 
15.03.13
10:09
(41) при чем тогда здесь "чтобы все было по-честному" и "на один телевизор 5000 ручек"?..
45 Xapac_2
 
15.03.13
10:15
(0) ладно уговорил давай логин пароль посмотрим.
46 Лефмихалыч
 
15.03.13
10:38
все гораздо проще на самом деле

ТаблицаПодарков = новый ТаблицаЗначений;
ТаблицаПодарков.Колонки.Добавить("ИндексПодарка");
ТаблицаПодарков.Колонки.Добавить("Верятность");

ТаблицаПодарков.Добавить();// 1>>20
ТаблицаПодарков.Добавить();// 2>>30
ТаблицаПодарков.Добавить();// 3>>10


ТаблицаВыбора = Новый ТаблицаЗначений;
ТаблицаВыбора.Колонки.Добавить("ИндексПодарка");
ТаблицаВыбора.Колонки.Добавить("Сортировка");

ГСЧ = Новый ГенераторСлучайныхЧисел(ТекущаяДата()-Дата(1,1,1));

Для каждого ТаблицаПодарковСтрока Из ТаблицаПодарков Цикл
   Для СчЦ=1 По ТаблицаПодарковСтрока.Вероятность Цикл
       Строка = ТаблицаВыбора.Добавить();
       Строка.ИндексПодарка = ТаблицаПодарковСтрока.ИндексПодарка;
       Строка.Сортировка = ГСЧ.СлучайноеЧисло();
   КонецЦикла;
КонецЦикла;

ТаблицаВыбора.Сортировать("Сортировка");


И дальше уже выбирать из таблицы выбора строки по очереди. Получится искомое распределение - первый подарок будет выбран с вероятностью 20/60, второй - 30/60 и третий - 10/60
47 acsent
 
15.03.13
10:42
(46) так надо не все строки выбрать а одну
48 Лефмихалыч
 
15.03.13
10:43
(47) при оформлении каждой отдельной накладной выбираетсмя одна строка из ТаблицаВыбора и по ней определяется одна строка из ТаблицаПодарков. Откуда ты взял выбор всех строк, расскажи?
49 sda553
 
15.03.13
10:48
Все не читал, автора какой нибудь телепат смог понять?
50 YHVVH
 
15.03.13
10:59
(49) если я правильно понял
вероятность - это вес строки, строки с большим весом
должны выбираться чаще.
51 dk
 
15.03.13
11:16
(46) в (21) тоже самое
52 Лефмихалыч
 
15.03.13
13:16
(51) возможно. я там ни фига не понял
53 shpioleg
 
15.03.13
14:54
Сделал вот для своих целей. Для Номенклатуры тоже сгодится, если добавить реквизит ВероятностьУчастияВАкции. Блок кода который делит вероятности на более мелкие части (тут в ветке кто-то жаловался на неравномерное распределение) можно выкинуть.

&НаСервереБезКонтекста
Функция ПолучитьСлучайныйПунктНаСервере ()
   ЧислоРазрезкиВероятности = 1;// Число разрезаний исходной ТЗ на более мелкие части вероятностей. Если 0, то не разрезаем
   Запрос = Новый Запрос;
   Запрос.Текст =
   "ВЫБРАТЬ
   |    Ссылка,
   |    ВероятностьПоездки Вероятность
   |ИЗ
   |    Справочник.Пункты
   |ГДЕ
   |    ВероятностьПоездки > 0
   |    И НЕ ПометкаУдаления";
   ТЗРезультата = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.Прямой);
   Если НЕ ТЗРезультата.Количество() Тогда Возврат Неопределено; КонецЕсли;
   ГСЧ = Новый ГенераторСлучайныхЧисел();
   //Чутка помешаем. Разобьем вероятность на ЧислоРазрезкиВероятности.Хз нужно ли это вообще для более равномерного распределения.
   Для ш = 1 по ЧислоРазрезкиВероятности Цикл
       ТЗДобавленныхВероятностей = ТЗРезультата.СкопироватьКолонки();
       Для каждого стрТЗРезультата из ТЗРезультата Цикл
           СлучайноеЧисло = ГСЧ.СлучайноеЧисло(0,стрТЗРезультата.Вероятность - 1);                            
           Если СлучайноеЧисло Тогда
               стрТЗРезультата.Вероятность = стрТЗРезультата.Вероятность - СлучайноеЧисло;
               НоваяСтрока = ТЗДобавленныхВероятностей.Добавить();
               НоваяСтрока.Ссылка = стрТЗРезультата.Ссылка;
               НоваяСтрока.Вероятность = СлучайноеЧисло;            
           КонецЕсли;
       КонецЦикла;
       Для каждого стрТЗДобавленныхВероятностей из ТЗДобавленныхВероятностей Цикл
           НоваяСтрока = ТЗРезультата.Добавить();
           НоваяСтрока.Ссылка = стрТЗДобавленныхВероятностей.Ссылка;
           НоваяСтрока.Вероятность = стрТЗДобавленныхВероятностей.Вероятность;        
       КонецЦикла;
   КонецЦикла;
   //Найдем в ТЗ строку соответствующую Случайному числу
   СлучайноеЧисло = ГСЧ.СлучайноеЧисло(1,ТЗРезультата.Итог("Вероятность"));
   Для каждого стрТЗРезультата из ТЗРезультата Цикл
       СлучайноеЧисло = СлучайноеЧисло - стрТЗРезультата.Вероятность;
       Если СлучайноеЧисло <= 0 Тогда
           Возврат (стрТЗРезультата.Ссылка);
       КонецЕсли;
   КонецЦикла;
   Возврат Неопределено;
КонецФункции
&НаКлиенте
Процедура ПолучитьСлучайныйПункт(Команда)
   Сообщить (ПолучитьСлучайныйПунктНаСервере ());
КонецПроцедуры
54 NcSteel
 
15.03.13
15:15
(0) Пишешь алгоритм для рекламных банеров?
55 Torquader
 
15.03.13
19:07
Если у вас есть события с разной вероятностью - то это отрезок, разбитый на части, которые пропорциональны вероятности событий.
В строгой теории длина отрезка всегда равна единице, но может и отличаться.
В случае единицы мы просто генерим случайное число от 0 до 1 и "кидаем" его на отрезок.
В чью часть отрезка оно попало - того и выбрали.
Конечно, для правильности выбора нужен равномерный случайный генератор.
P.S. если сумма вероятностей не ноль, то генерим случайное число, равное длине отрезка.
56 HeroShima
 
16.03.13
19:01