Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Geometric Distribution Examples

Boost , Math Toolkit 2.5.0 , Worked Examples

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

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

#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error
#define BOOST_MATH_DISCRETE_QUANTILE_POLICY real
[Caution] Caution

Важно #включить дистрибутивы и т.д.послевышеупомянутые определения

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

#include <boost/math/distributions/geometric.hpp>
  // for geometric_distribution
  using ::boost::math::geometric_distribution; //
  using ::boost::math::geometric; // typedef provides default type is double.
  using  ::boost::math::pdf; // Probability mass function.
  using  ::boost::math::cdf; // Cumulative density function.
  using  ::boost::math::quantile;
#include <boost/math/distributions/negative_binomial.hpp>
  // for negative_binomial_distribution
  using boost::math::negative_binomial; // typedef provides default type is double.
#include <boost/math/distributions/normal.hpp>
  // for negative_binomial_distribution
  using boost::math::normal; // typedef provides default type is double.
#include <iostream>
  using std::cout; using std::endl;
  using std::noshowpoint; using std::fixed; using std::right; using std::left;
#include <iomanip>
  using std::setprecision; using std::setw;
#include <limits>
  using std::numeric_limits;

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

Простые блоки «попробовать» (см. ниже) гарантируют, что вы получите полезное сообщение об ошибке вместо резкого (и тихого) прерывания программы.

Throwing a dice

Геометрическое распределение описывает вероятность (р) ряда неудач получить первый успех в.kИспытания Бернулли.Испытание Бернулли— это испытание, в котором возможны только два исхода, успех неудачи иp— вероятность успеха.

Предположим, что «справедливая» 6-лицевая кость бросается несколько раз:

double success_fraction = 1./6; // success_fraction (p) = 0.1666
// (so failure_fraction is 1 - success_fraction = 5./6 = 1- 0.1666 = 0.8333)

Если кости бросаются многократно до тех пор, пока не появитсяпервыйразтри. Распределение вероятностей числа раз, когда оно выбрасываетсяне, получаятрине-тричисло отказов получитьтри, является геометрическим распределением с успехом_фракцией = 1/6 = 0,166 ̇.

Поэтому мы начинаем с построения геометрического распределения с одним параметром «успех-фракция» — вероятностью успеха.

geometric g6(success_fraction); // type double by default.

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

cout << "success fraction of a six-sided dice is " << g6.success_fraction() << endl;

Так что вероятность получить три при первом броске (ноль отказов) равна

cout << pdf(g6, 0) << endl; // 0.1667
cout << cdf(g6, 0) << endl; // 0.1667

Обратите внимание, что cdf и pdf идентичны, потому что это только один бросок. Если мы хотим получить первыйтрина 2-м броске:

cout << pdf(g6, 1) << endl; // 0.1389

Если мы хотим получить первыйтрина 1-м или 2-м броске (позволяя один сбой):

cout << "pdf(g6, 0) + pdf(g6, 1) = " << pdf(g6, 0) + pdf(g6, 1) << endl;

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

cout << "cdf(g6, 1) = " << cdf(g6, 1) << endl; // 0.3056

Если допустить еще много (12) бросков, то вероятность получить нашитристановится очень высокой:

cout << "cdf(g6, 12) = " << cdf(g6, 12) << endl; // 0.9065 or 90% probability.

Если мы хотим быть более уверенными, скажем, на 99%, мы можем оценить количество бросков, используя обратный или квантиль.

cout << "quantile(g6, 0.99) = " << quantile(g6, 0.99) << endl; // 24.26

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

См.толкование дискретных квантилей.

Геометрическое распределение связано с отрицательным биномиалом   <negative_binomial_distribution(RealTyper,RealType p);>с параметромr= 1. Таким образом, мы могли бы получить тот же результат, используя отрицательный биномиал, но используя геометрический результат будет быстрее и может быть более точным.

negative_binomial nb(1, success_fraction);
cout << pdf(nb, 1) << endl; // 0.1389
cout << cdf(nb, 1) << endl; // 0.3056

Мы могли бы также дополнить выражение требуемой вероятности как 1 - 0,99 = 0,01 (и получить тот же результат):

cout << "quantile(complement(g6, 1 - p))  " << quantile(complement(g6, 0.01)) << endl; // 24.26

Обратите внимание и на этот рост. Математическое геометрическое распределение реализуется как непрерывная функция. В отличие от других реализаций (например, R) ониспользуетчисло отказов какреальныйпараметр, а не как целое число. Если вы хотите, чтобы это поведение было целым, вам, возможно, придется применить это, округляя параметр, который вы проходите, вероятно, округляя вниз, до ближайшего целого числа. Например, R возвращает вероятность дроби успеха для всех значений отказов от 0 до 0,999999 таким образом:

   R> formatC(pgeom(0.0001,0.5, FALSE), digits=17) "               0.5"

Так что в Буст. Математика эквивалентна

    geometric g05(0.5);  // Probability of success = 0.5 or 50%
    // Output all potentially significant digits for the type, here double.
#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS
  int max_digits10 = 2 + (boost::math::policies::digits<double, boost::math::policies::policy<> >() * 30103UL) / 100000UL;
  cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined" << endl;
#else
  int max_digits10 = std::numeric_limits<double>::max_digits10;
#endif
  cout << "Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = "
    << max_digits10 << endl;
  cout.precision(max_digits10); //
    cout << cdf(g05, 0.0001) << endl; // returns 0.5000346561579232, not exact 0.5.

Чтобы получить дискретное поведение R, вам просто нужно округлить, например, с функцией<floor>.

cout << cdf(g05, floor(0.0001)) << endl; // returns exactly 0.5
> formatC(pgeom(0.9999999,0.5, FALSE), digits=17) [1] "              0.25"
> formatC(pgeom(1.999999,0.5, FALSE), digits=17)[1] "              0.25" k = 1
> formatC(pgeom(1.9999999,0.5, FALSE), digits=17)[1] "0.12500000000000003" k = 2

показывает, что R принимает произвольное решение о округлении примерно на 1e7 от следующего целого числа выше. Это может быть удобно на практике и при желании может быть воспроизведено на C++.

Surveying customers to find one with a faulty product

Компания знает из гарантийных требований, что 2% их продуктов будут неисправными, поэтому «успешность» обнаружения неисправности составляет 0,02. Он хочет опросить покупателя неисправных продуктов, чтобы оценить их «опыт пользователя».

Чтобы оценить количество клиентов, с которыми им, вероятно, придется связаться, чтобы найти того, кто пострадал от ошибки, мы сначала строим геометрическое распределение с вероятностью 0,02, а затем выбираем уверенность, скажем, 80%, 95% или 99%, чтобы найти клиента с ошибкой. Наконец, мы, вероятно, хотим округлить результат до целого числа выше с помощью функции<ceil>. (Мы также можем использовать политику, но это вряд ли стоит для этого простого приложения.)

(Это также предполагает, что каждый клиент покупает только один продукт: если клиенты купили более одного предмета, вероятность найти клиента с ошибкой явно повышается.)

cout.precision(5);
geometric g(0.02); // On average, 2 in 100 products are faulty.
double c = 0.95; // 95% confidence.
cout << " quantile(g, " << c << ") = " << quantile(g, c) << endl;
cout << "To be " << c * 100
  << "% confident of finding we customer with a fault, need to survey "
  <<  ceil(quantile(g, c)) << " customers." << endl; // 148
c = 0.99; // Very confident.
cout << "To be " << c * 100
  << "% confident of finding we customer with a fault, need to survey "
  <<  ceil(quantile(g, c)) << " customers." << endl; // 227
c = 0.80; // Only reasonably confident.
cout << "To be " << c * 100
  << "% confident of finding we customer with a fault, need to survey "
  <<  ceil(quantile(g, c)) << " customers." << endl; // 79
Basket Ball Shooters

Согласно Википедии, средний игрок в корзину получаетбесплатные броскив корзинах от 70 до 80% времени, но некоторые получают до 95%, а другие до 50%. Предположим, мы хотим сравнить вероятность того, что мы не получим результат только на первом или пятом ударе. Для начала рассмотрим средний стрелок, скажем 75%. Таким образом, мы строим геометрическое распределение с параметром успешности_фракции 75/100 = 0,75.

cout.precision(2);
geometric gav(0.75); // Shooter averages 7.5 out of 10 in the basket.

Какова вероятность получить 1-ю попытку в корзине, то есть без сбоев?

cout << "Probability of score on 1st try = " << pdf(gav, 0) << endl; // 0.75

Это, конечно же, вероятность успешности-фракции 75%. Какова вероятность того, что стрелок забьет только на пятом выстреле? 5-1 = 4 неудачи перед первым успехом.

cout << "Probability of score on 5th try = " << pdf(gav, 4) << endl; // 0.0029

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

geometric gbest(0.95);
cout << "Probability of score on 5th try = " << pdf(gbest, 4) << endl; // 5.9e-6
geometric gmediocre(0.50);
cout << "Probability of score on 5th try = " << pdf(gmediocre, 4) << endl; // 0.031

Таким образом, мы видим гораздо меньший шанс (0,000006) из 4 неудач лучших стрелков, по сравнению с 0,03 посредственных.

Estimating failures

Конечно, неудача одного человека — это успех другого. Таким образом, ошибку можно определить как «успех».

Если неисправность возникает один раз после 100 полетов, то можно наивно сказать, что риск неисправности составляет, очевидно, 1 к 100 = 1/100, вероятность 0,01.

Это лучшая оценка, которую мы можем сделать, но, хотя это правда, это не вся правда, поскольку она скрывает большую неопределенность при оценке из одного события. «Одна ласточка не делает лето». Чтобы показать величину неопределенности, можно использовать геометрическое (или отрицательное биномиальное) распределение.

Если мы выберем популярное 95%-ное доверие к пределам, соответствующее альфа 0,05, потому что мы вычисляем двусторонний интервал, мы должны разделить альфа на два.

double alpha = 0.05;
double k = 100; // So frequency of occurrence is 1/100.
cout << "Probability is failure is " << 1/k << endl;
double t = geometric::find_lower_bound_on_p(k, alpha/2);
cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
  << t << endl; // 0.00025
t = geometric::find_upper_bound_on_p(k, alpha/2);
cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
  << t << endl; // 0.037

Таким образом, хотя мы оцениваем вероятность 0,01, она может лежать между 0,0003 и 0,04. Даже если мы ослабим нашу уверенность в альфа = 90%, границы сжимаются только до 0,0005 и 0,03. И если мы требуем высокой уверенности, они расширяются до 0,00005 до 0,05.

alpha = 0.1; // 90% confidence.
t = geometric::find_lower_bound_on_p(k, alpha/2);
cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
  << t << endl; // 0.0005
t = geometric::find_upper_bound_on_p(k, alpha/2);
cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
  << t << endl; // 0.03
alpha = 0.01; // 99% confidence.
t = geometric::find_lower_bound_on_p(k, alpha/2);
cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
  << t << endl; // 5e-005
t = geometric::find_upper_bound_on_p(k, alpha/2);
cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
    << t << endl; // 0.052

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

Как отмечалось выше, использование блок-уловки всегда хорошая идея, даже если вы надеетесь не использовать его!

}
catch(const std::exception& e)
{ // Since we have set an overflow policy of ignore_error,
  // an overflow exception should never be thrown.
   std::cout << "\nMessage from thrown exception was:\n " << e.what() << std::endl;

Например, без игнорирования политики ошибки домена, если мы просим

pdf(g, -1)

Например, мы получим бесполезный аборт, но с уловкой:

Message from thrown exception was:
 Error in function boost::math::pdf(const exponential_distribution<double>&, double):
 Number of failures argument is -1, but must be >= 0 !

См. полный источник C++ этого примера по адресуgeometry_examples.cpp

См. пример отрицательного биномиального доверительного интервала.


PrevUpHomeNext

Статья Geometric Distribution Examples раздела Math Toolkit 2.5.0 Worked Examples может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: Worked Examples ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 08:31:58/0.0093660354614258/0