kontinuierliche Werte (doubles) diskretisieren



  • Hallo ihr Lieben,

    ich habe (wahrscheinlich) eine sau dumme bzw. einfach Frage:
    Wie diskretisiere ich ein Intverall anständig?

    Ich spiele z.B. gerden mit den Zufallsgeneratoren von C++ herum und will mir die Verteilung von auf [0,1) gleichmäßig verteilten Zufallszahlen anschauen:

    #include <iostream>
    #include <vector>
    #include <random>
    
    using namespace std;
    
    int main()
    {
    const double x_min(0.0), x_max(1.0), dx(0.1);
    const unsigned int samplingPoints = (x_max - x_min) / dx;
    vector<unsigned long int> results(samplingPoints,0);
    
    random_device seed;
    
    mt19937 engine(seed());
    
    unsigned int const runs = 1e6;
    
    for(unsigned int i = 0; i < runs; ++i)
    {
    	double value = generate_canonical<double,10>(engine); 
    	unsigned int slot = value / dx;
    	++results[slot];
    }
    
    for(unsigned int i = 0; i < results.size(); ++i)
    	cout << static_cast<double>(i) * dx << "  " << results[i] << endl;
    
    return 0;
    }
    

    Dazu unterteile ich das Intervall, bestehend aus den Grenzen x_min und x_max durch die Schrittweite dx.
    Jetzt geht die Problematik aber schon los: In diesem einfachen Beispiel hätte ich jetzt 10 Teilintervalle aber 11 Stützstellen, eigentlich ist die Anzahl der Stützstellen immer gleich #Teilintervalle +1.
    Und das zeigt sich auch später bei der Ausgabe, die von 0 bis 0.9 geht, wohlwissen, dass das Teilintervall 0.9 alles bis zur Obergrenze x_max = 1 abgdeckt.

    Und intuitiv würde man auch die Stützstellen, eher in die Mitte der Intervalle legen, oder nicht? Also 0.05, 0.15, ..., 0.95. Dann wären auch die Anzahl der Stützstellen gleich der Anzahl der Teilintervalle.

    Wie mache ich das denn richtigtm.

    Eine Möglichkeit ist natürlich das dx immer kleiner zu machen. Aber ich schätze, dass diese Diskretisierung eine ausgiebig untersuchte Wissenschaft für sich ist.

    Mein google-fu führt mich allerdings nur zur Diskretisierung zwecks numerischem lösen von DGLs.

    Was ist denn für meine Problematik das richtige Schlagwort?

    Gruß,
    -- Klaus.


  • Mod

    Ich glaube, ich verstehe dein Problem nicht. Kannst du etwas ausführlicher werden? vielleicht mit Beispiel?

    Nichtsdestotrotz schlage ich die Verbesserung vor, dass du nicht dx als Grundgröße nimmst, sondern die Anzahl der Bins, damit alle Bins gleich groß sind. Außerdem habe ich deinem Beispiel noch eingefügt, dass es auch mit x_min ungleich 0 zurecht kommt und ein paar kleine Detailsverbesserungen:

    #include <iostream>
    #include <vector>
    #include <random>
    
    using namespace std;
    
    int main()
    {
      const double x_min(0.0), x_max(1.0);
      const unsigned int samplingPoints = 10;
      const double dx = (x_max - x_min) / samplingPoints;
      vector<unsigned long int> results(samplingPoints,0);
    
      random_device seed;
    
      mt19937 engine(seed());
    
      unsigned int const runs = 1e6;
    
      for(unsigned int i = 0; i < runs; ++i)
        {
          double value = generate_canonical<double,10>(engine);
          unsigned int slot = (value - x_min) / dx;
          ++results[slot];
        }
    
      for(unsigned int i = 0; i < results.size(); ++i)
        cout << "Von " << x_min + i * dx << " bis " << x_min + (i+1) *dx 
             << "  " << results[i] << '\n';
    }
    

    edit: Oder suchst du einfach folgende, gewaltige, mathematische Erkenntnis?

    cout << x_min + (i+0.5) * dx << "  " << results[i] << '\n';
    


  • Stützstellen

    Ich sehe keine Stuetzstellen. Was meinst du damit? Vielleicht solltest du dich ganz von dem Begriff loesen und einfach mit Intervallen arbeiten. Dein Index i repreasentiert ein bestimmtes Intervall, bspw. i=0 ist Intervall [0:0.1) ... i=9 ist [0.9;1.0);

    Verteilung

    Du meinst sicherlich Dichte.



  • Guten Morgen,

    SeppJ schrieb:

    Ich glaube, ich verstehe dein Problem nicht. Kannst du etwas ausführlicher werden? vielleicht mit Beispiel?

    Ja, wenn man eine Frage nicht eindeutig formulieren kann, dann hat man das zugrunde liegende Problem noch nicht voll erfasst. 😃

    Ich probier mich. Ich denke mit knivils Kommentar lassen sich meine Gedankengänge am Besten beschreiben:

    knivil schrieb:

    [..] Vielleicht solltest du dich ganz von dem Begriff loesen und einfach mit Intervallen arbeiten. Dein Index i repreasentiert ein bestimmtes Intervall, bspw. i=0 ist Intervall [0:0.1) ... i=9 ist [0.9;1.0);

    Verteilung

    Du meinst sicherlich Dichte.

    Meiner Meinung nach beschreibt dieser Kommentar genau den Widerspruch, den ich verstehen möchte: Wenn ich mein Intervall [0,1) in zehn Teilintervalle (Bins?) zerlege, dann habe ich als Ergebnis effektiv ein Histogramm. Wenn ich es derart auftrage, dann zeigt das Ergebnis zehn mögliche Ausgänge. Ich betreibe damit diskrete Wahrscheinlichkeitstheorie. Wenn ich den Code etwas modifiziere

    for(unsigned int i = 0; k < results.size(); ++k)
      cout << "Von " << x_min + k * dx << " bis " << x_min + (k+1) *dx 
           << "  " << results[k] / static_cast<double>(runs) << '\n';
    

    dann gibt die Höhe der Balken die (genäherte) Wahrscheinlichkeit an, ich kann sagen:
    P(X\in [x\_i,x\_{i+1})) = 0.1

    Jetzt sagt aber knivil (nochmal)

    knivil schrieb:

    [..]

    Verteilung

    Du meinst sicherlich Dichte.

    Die Dichte f(x) ist ein Begriff, der mit kontinuierlichen Verteilungen zu tun hat. Allgemein gilt für eine Dichte für eine auf einem Intervall [a,b) gleichmäßig verteilte Zufallsvariable
    f(x) = \frac{1}{b-a} 1_{[a,b)}
    In meinem Fall f(x) = 1_{[0,1)}

    So, wie kriege ich also ein kontinuierliches Ergebnis? Nach meiner naiven Auffassung gibt es im Rahmen der Programmierung nicht kontinuierliches, da ich immer gezwungen bin mit Intervallen zu arbeiten. Ich kann die Länge der Intervalle allerdings sehr klein machen, sodass die Kurve bei anschließender graphischer Auftragung kontinuierlich aussieht.

    Also kann ich dieses Prozedere auch auf meinen Algorithmus anwenden, ich verkleinere dx auf 0.01, 0.001 oder 0.0001. Damit werden die Balken des Historgramms immer schmaler und im Rahmen der diskreten Wahrscheinlichkeit wird
    P(X\in [x\_i,x\_{i+1}) ) = 0.01 = 0.001 = 0.0001

    Wenn ich das aber graphisch auftrage, dann werden meine Balken auch immer niedriger. Was ich doch aber möchte - um mit der kontinuierlichen Dichte aufzuschließen - ist eine Gerade, die zwischen 0 und 1 den Wert 1 hat!

    Gruß,
    -- Klaus.



  • Wenn die Intervalle kleiner werden, muss die Anzahl der Ziehungen groesser werden. Desweiteren schaetzt du nur die Dichte durch eine Stichprobe. Ich wuerde weiterhin eine Normierung durch die Anzahl der Stichproben (und vielleicht Intervallbreite) vorschlagen, da viele Stichproben einen anderen Graphen produzieren als wenige.


  • Mod

    Der double hat ohnehin nur eine endliche Zahl von Zustanden zwischen 0 und 1*. Er kann zwar teilweise sehr fein auflösen, aber irgendwann wirst du doch die Diskretisierung der Werte sehen.

    *: Zudem sind sie noch logarithmisch verteilt


Anmelden zum Antworten