Russian Qt Forum
Сентябрь 23, 2024, 20:21 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Разобрать программу по теории Пирсона  (Прочитано 3006 раз)
lexflax
Гость
« : Май 27, 2014, 12:51 »

Доброго времени суток.
Сдал первую лабу по методу Монте-Карло..
Вторая лаба Цель работы: изучить методы моделирования нормально распределенных случайных величин и проверки их с помощью критерия Пирсона.
Есть прога готовая, но по тексту программы во многих местах не понимаю что, где и как делается... от части потому что саму математическую модель не понимаю ... от части некоторый код просто не понимаю...
Помогите разобратся в самом коде, я некоторые комментарии проставил но не факт что они верные... помогите проставить комментарии везде? и собственно понять саму проверку с помощью Пирсона может в более простом варианте объяснения? Просто те которые сижу читаю и пытаюсь понять , не могу осмыслить мат знаний не хватает...
mainwindows.cpp
Код:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "stdlib.h"
#include "time.h"
#include "QDebug"
#include "math.h"
#include <QGraphicsScene>
 
float chi2inv(float a, int n);
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    n=6;
    pi=M_PI;
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
 
float MainWindow::r()
{
    float r= (float) rand() / RAND_MAX;
    return r;
}
 
void MainWindow::on_pushButton_clicked()
{
    srand(time(NULL));
    r_count=ui->sb_r_count->value();//количество случайных чисел
    mx=ui->dsb_mx->value();//математическое ожидание
    dx=ui->dsb_dx->value();//средне квадратичное отклонение
    z.clear();
    x.clear();
    v.clear();
    fi.clear();
    fp.clear();
    xi.clear();
    xip.clear();
    for(int i=0;i<r_count;i++)// цикл по случайным числам
        for(int j=0;j<n;j++) //цикл по количеству эксперементов
        {
            if (j==0) v.append(r()); //если первый эксперемент то записать в конец строки v значение r
            else v[i]+=r();// иначе заполнять массив увеличивая каждый раз на значение r
        }
    for(int i=0;i<r_count;i++)// цикл по случайным числам
    {
        z.append((v[i]-(n/2.0))/sqrt(n/12.0));// не понимаю формулу
    }
    for(int i=0;i<r_count;i++)// цикл по случайным числам
    {
        x.append(mx+z[i]*dx); //не понимаю формулу
    }
 
    for(int i=0;i<r_count;i++)// цикл по случайным числам
    {
        int j=fi.indexOf((int)(x[i]*10));
 
        if(j==-1)
        {
            fi.append((int)(x[i]*10));
 
            fp.append(1);
        }
        else
        {
            fp[j]+=1;
        }
    }
    for(int i=0;i<fi.count();i++)// цикл по случайным числам
    {
        qDebug()<<"значения х:"<<fi[i]<<" вероятность: "<<fp[i];
    }
    int count=0;
    for(int i=0;i<fi.count();i++)// цикл по случайным числам
    {
        count+=fp[i];
    }
    qDebug()<<"Itogo: "<<count;
    this->update();
 
    float pi2=sqrt(2.0*pi);
    for(float i=(mx-4*dx);i<=(mx+4*dx);i+=0.1)
 
 
    {
        xi.append(i*10);
 
        xip.append((1.0/(dx*pi2))*exp(-((i-mx)*(i-mx))/(2.0*dx*dx)));
    }
 
    QGraphicsScene *scena=new QGraphicsScene;
 
 
    scena->addLine(200,150,200,0,QPen(Qt::black));
    scena->addLine(0,150,600,150,QPen(Qt::black));
    for(int i=0;i<61;i++)
        {
            scena->addLine(i*10,150-5,i*10,150+5,QPen(Qt::black));
        }
    for(int i=0;i<31;i++)
        {
            scena->addLine(i*100,150-10,i*100,150+10,QPen(Qt::black));
        }
        for(int i=0;i<fi.count();i++)
        {
 
            scena->addEllipse(200+fi[i],150-10000*fp[i]/r_count,1,1,QPen(Qt::black));
 
        }
        for(int i=0;i<xi.count();i++)
        {
            scena->addEllipse(200+xi[i],150-xip[i]*1000,1,1,QPen(Qt::red));
        }
        xiexp=0.0;
        int countxi=xi.count();
        int ix=0;
        float rc=(float)r_count;
 
 
        for(ix=0;ix<countxi;ix++)
        {
            int jf=0;
            while(xi[ix]!=fi[jf] && jf<fi.count()-1){jf++;}
 
                xiexp+=0.1*((fp[jf]-xip[ix]*r_count)*(fp[jf]-xip[ix]*r_count))/((xip[ix])*r_count);
 
        }
 
        ui->label_3->setText(QString::number(xiexp));
 ui->graphicsView->setScene(scena);
 
 float min=chi2inv(1-0.01,r_count-3);
 float min25=chi2inv(1-0.25,r_count-3);
 float mid=chi2inv(1-0.5,r_count-3);
 float mid75=chi2inv(1-0.75,r_count-3);
 float max=chi2inv(1-0.999,r_count-3);
 
 
ui->label_4->setText(QString::number(mid));
 ui->label_5->setText(QString::number(max));
 ui->label_10->setText(QString::number(min));
 ui->label_12->setText(QString::number(min25));
 ui->label_14->setText(QString::number(mid75));
 
 
}
 
float chi2inv(float a, int n) {
    float d;
    if(a >= 0.001 && a < 0.5)
        d = - 2.0637 * pow((log(1.0/a) - 0.16), 0.4274) + 1.5774;
    else if(a <= 0.999)
        d = 2.0637 * pow((log(1.0/(1 - a)) - 0.16), 0.4274) - 1.5774;
    else
        return 0;
    float A = d * sqrt(2);
    float B = 2.0/3 * (d * d - 1);
    float C = d * (d * d - 7)/(9 * sqrt(2));
    float D = (6 * pow(d, 4) + 14 * d * d - 32)/405;
    float E = d * (9 * pow(d, 4) + 256 * d * d - 433) / (4860 * sqrt(2));
    return n + A * sqrt(n) + B + C/sqrt(n) + D/n + E/(n*sqrt(n));
}
main.cpp
Код:
#include <QtGui/QApplication>
#include "mainwindow.h"
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
 
    return a.exec();
}
mainwindows.h
Код:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include <QVector2D>
#include "QPainter"
namespace Ui {
    class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    float r();
    int r_count;
    int n;
    QVector<float> v;
    QVector<float> z;
    QVector<float> x;
    float mx;
    float dx;
    float pi;
    QVector<float> fi;
    QVector<float> fp;
    QVector<float> xi;
    QVector<float> xip;
    float xiexp;
 
private slots:
    void on_pushButton_clicked();
 
private:
    Ui::MainWindow *ui;
};
 
#endif // MAINWINDOW_H
Записан
vizir.vs
Гость
« Ответ #1 : Май 27, 2014, 16:03 »

Здесь используется ЦПТ. Суть ее в том, что ты генеришь несколько выборок распределенных по равномерному закону (обычно от 12 выборок, но в вашем коде почему то только 6 (n=6)), а затем объединяешь их в одну выборку и получается нормальная выборка с параметрами 0;1.
Код:
z.append((v[i]-(n/2.0))/sqrt(n/12.0)); 
это и есть объединение всех выборок в одну выборку.
Так как нам нужна нормальная выборка, но с другими параметрами вы делаем следующие
Код:
x.append(mx+z[i]*dx);

Вот здесь написано как можно моделировать нормальное распределение. (http://ru.wikipedia.org/wiki/%D0%9D%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D1%80%D0%B0%D1%81%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5). Я сам раньше использовал для этого преобразование Бокса-Мюллера. Ну и у буста есть встроенные генераторы случайных чисел с различным распределением. Последнее время я его использую.
Вот здесь пункт Г (http://www.ipages.ru/index.php?ref_item_id=116&ref_dl=1) более подробно объясняется как генерировать нормальный закон используя цпт.
Что касается самого Пирсона, то суть его проста:
1. Разделить все пространство от минимума и до максимума на отрезки. Обычно используется формула 3,31ln n + 1. Где n-число элементов в выборке, но есть и другие формулы http://ami.nstu.ru/~headrd/seminar/publik_html/Z_lab_8.htm
2. Шаг второй - считаем количество элементов, которые попали в соответствующий интервал.
3. Шаг третий - смотрим разницу. Для этого суммируем по всем интервалам квадрат разницы между тем, сколько у нас попало элементов деленое на общее количество элементов и из дроби вычитаем вероятность попадания в интервал. Все это возводим в квадрат и делим на вероятность попадание в интервал. Полученную сумму умножаем на число элементов.
Вот эта вычисление
Код:
xiexp+=0.1*((fp[jf]-xip[ix]*r_count)*(fp[jf]-xip[ix]*r_count))/((xip[ix])*r_count);. 
Только я не совсем понял, почему здесь 0.1.  Да и вообще периодически проскакивает умножение на 10, которое мне не очень понятно.

Вот собственно и все.
Вот это:
Код:
 float min=chi2inv(1-0.01,r_count-3);
 float min25=chi2inv(1-0.25,r_count-3);
 float mid=chi2inv(1-0.5,r_count-3);
 float mid75=chi2inv(1-0.75,r_count-3);
 float max=chi2inv(1-0.999,r_count-3);
смотрит значение критерия пирсона при различном уровне значимости. Дальше глядим в таблицы и  принимаем решение о принятие нулевой гипотезы (полученное распределение совпадает с предполагаемым) или отвергаем эту гипотезу (это нефига не наше распределение).

P.S. Я бы выбросил эту прогу и переписал бы. Мух отдельно, котлеты отдельно. Да и магических чисел хватает.
« Последнее редактирование: Май 27, 2014, 16:20 от vizir.vs » Записан
Lagovas
Гость
« Ответ #2 : Май 29, 2014, 01:21 »

Пол года назад делал преподу методу по лабе на эту тему. Только там python + orange. Делал конечно на отмашку, но помню сам тогда разобрался. Если интересует, обращайтесь через емейл.
Записан
vizir.vs
Гость
« Ответ #3 : Май 29, 2014, 15:11 »

Я диссер пишу, у меня там используется нормальное распределение и критерий Пирсона для проверки на нормальность. Пишу все на Qt + C++
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.131 секунд. Запросов: 20.