Script mehrfach ausführen und Median berechnen.

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Schwervisuell
User
Beiträge: 2
Registriert: Montag 5. August 2019, 14:53

Guten Tag liebe Mitglieder des Python-Forums,

wie ihr dem Code sicherlich gleich entnehmen könnt, bin ich noch sehr neu in der Materie des Programmierens. Ich möchte gerne das folgende Script mehrfach (um genau zu sein mehrere hundert mal) nacheinander durchführen, jeweils die Abweichung "zwischenspeichern" und dann anschließend den Median daraus bilden.

Code: Alles auswählen

import numpy
import math

n = Anzahl Punkte

x = numpy.random.uniform(-1, 1, (n, 1))
y = numpy.random.uniform(-1, 1, (n, 1))

kreis = (x)**2 + (y)**2 <= 1

xin = x[kreis]
yin = y[kreis]

pi = (4 * numpy.sum(kreis) / n)

print("Approximiertes Pi:", pi)
print("Faktisches Pi:", round(math.pi, 10))
print("Abweichung:", abs(pi - round(math.pi, 10)))
Würde mich sehr freuen, wenn mir da jemand helfen könnte. Wäre auch schon für das ein oder andere Schlagwort dankbar, nachdem ich dann googeln könnte :)

Mit freundlichen Grüßen
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Schwervisuell: Die Stichworte wären Funktionen, also selber eine schreiben, und Schleifen, um die selbst geschriebene Funktion dann mehrere hundert mal aufzurufen.

Wobei falls das jetzt nicht den Arbeitsspeicher sprengt: Du könntest statt das mehrere hundert mal aufzurufen auch eine weitere Dimension zu den Daten hinzufügen und die Schleife effektiv in Numpy ”verschieben”.

`xin` und `yin` werden definiert, aber nicht verwendet.

Die Klammern um `x` und `y` bei der Berechnung von `kreis` machen keinen Sinn. `kreis` ist auch kein so wirklich guter Name. `n` auch nicht zwingend. Verwende sprechende Bezeichner die aussagen was die Werte bedeuten. Also beispielsweise `anzahl_punkte` statt `n`. Bei `kreis` fällt mir so auf Anhieb nichts passendes ein, was ein Hinweis auf eine nicht ganz so günstige Aufteilung des Codes sein könnte. Wenn man das Aufsummieren dort schon macht, könnte man es `anzahl_punkte_im_kreis` nennen.

`round` braucht man nur recht selten wenn man wirklich mit einer gerundeten Zahl *weiterrechnen* will. Nachkommastellen für die Ausgabe legt man bei der Formatierung der Ausgabe als Zeichenkette fest. Beim Platzhalter für die `format()`-Methode oder ab Python 3.6 auch in f-Zeichenkettenliteralen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Beim Runden stellt sich mir die Frage, warum man unbedingt die Abweichung von auf 10 Stellen gerundetes PI wissen will.
`kreis` würde ich `punkte_innerhalb_kreis_maske` nennen.
Auch die Klammern bei der Berechnung von `pi` machen keinen Sinn. `pi` würde ich hier der Klarheit `genaehertes_pi´ nennen.
Schwervisuell
User
Beiträge: 2
Registriert: Montag 5. August 2019, 14:53

@__blackjack__

vielen Dank für deine Hinweise. Xin und Yin waren fürs spätere plotten - hab vergessen, den Bereich herauszunehmen, bevor ich den Beitrag gepostet habe. Die Bezeichnungen habe ich eindeutiger gestaltet (was mir tatsächlich sehr geholfen hat... werde ich zukünftig immer so machen).

Das mit den Funktionen und Schleifen habe ich versucht umzusetzen. Ich habe es so gelöst, dass das Script mir die Daten in eine externe .csv schreibt. Den Median würde ich dann einfach stumpf über Excel ausspucken lassen (oder von nem anderen Script). Damit gibts allerdings auch ein kleines Problem (siehe @Alle)

@Sirius3

vielen Dank - die Rundung sowie die überschüssigen Klammern habe ich entfernt.

@Alle

Dank eures Inputs bin ich schon deutlich weiter gekommen. Habe jetzt aber noch das Problem, dass die aktuelle Schleife 10x den gleichen Wert in eine .csv packt statt die Funktion 10 mal auszuführen und dann immer wieder den neuen Wert einzutragen. Vielleicht könnt ihr mir da nochmal helfen? Schonmal vielen Dank.

Code: Alles auswählen

#	Python 3.7.4

anzahl_punkte = 50000

x = numpy.random.uniform(-1, 1, (anzahl_punkte, 1))
y = numpy.random.uniform(-1, 1, (anzahl_punkte, 1))

in_kreis = x**2 + y**2 <= 1

pi = (4 * numpy.sum(in_kreis) / anzahl_punkte)

abw = abs(pi - math.pi)
string_abw = str(abw)

def werte_schreiben(string_abw):
    zwischenergebnisse = open("Zwischenpuffer.csv", "a")
    zwischenergebnisse.write(string_abw)
    zwischenergebnisse.write("\n")
    zwischenergebnisse.close()

anzahl_simulationen = 0
maximalanzahl_simulationen = 10

while anzahl_simulationen < maximalanzahl_simulationen:
    anzahl_simulationen = anzahl_simulationen + 1
    werte_schreiben(string_abw)
Vielen, vielen Dank schonmal.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Schwervisuell: Wieso sollte das nicht 10 mal das gleiche schreiben? Das ist doch genau das was Du dem Rechner sagst, berechne `string_abw`, und dann schreibt der das 10 mal in die Datei. Wenn Du die Berechnung 10 mal machen willst dann muss die in der Schleife gemacht werden, beziehungsweise sollte in der Schleife die Funktion die Du nicht geschrieben hast 10 mal aufgerufen werden.

Das mit der Datei ist aber auch unnötig kompliziert – sammel die Ergebnisse einfach in einer Liste und berechne dann davon den Median. Es gibt recht wenig Gründe das mit Excel, selbst wenn man nicht sowieso schon `numpy` verwenden würde, was dafür alles mitbringt, gäbe es sogar in der Python-Standardbibliothek ein passendes Modul.

Bei `abw`/`string_abw` bist Du dann wieder von den guten Namen weg.

Auf Modulebene sollte eigentlich nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Hauptprogramm und Funktionsdefinitionen auf Modulebene zu vermischen ist so ziemlich das unübersichtlichste was man machen kann.

Edit: Die ``while``-Schleife sollte eine ``for``-Schleife sein. Du weisst ja vorher wie oft die durchlaufen wird.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Hier mal 9 Simulationen die auch grafisch dargestellt werden, ohne eine einzige Schleife in Python zu schreiben:

Code: Alles auswählen

#!/usr/bin/env python3
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns


def main():
    anzahl_punkte = 50_000
    anzahl_simulationen = 9
    anzahl_beobachtungen = anzahl_punkte * anzahl_simulationen

    koordinaten = np.random.uniform(-1, 1, (2, anzahl_beobachtungen))
    simulationsnummern = (
        np.arange(anzahl_beobachtungen, dtype=int) // anzahl_punkte + 1
    )
    data = pd.DataFrame(
        {
            "Simulation": simulationsnummern,
            "x": koordinaten[0],
            "y": koordinaten[1],
        }
    )
    data["im Kreis"] = data.x ** 2 + data.y ** 2 <= 1
    print(data)
    
    sns.set()
    sns.set_style("white")
    sns.relplot(
        x="x",
        y="y",
        data=data,
        col="Simulation",
        col_wrap=3,
        hue=data["im Kreis"].map({True: "ja", False: "nein"}),
        height=2.5,
        alpha=0.2,
        edgecolor=None,
        s=0.5,
    )
    sns.despine(left=True, bottom=True)
    plt.savefig("test.png")

    abweichungen = (
        data[["Simulation", "im Kreis"]]
        .groupby("Simulation")
        .aggregate(lambda s: (4 * s["im Kreis"].sum() / s.count()) - np.pi)
        .abs()
        .rename(columns={"im Kreis": "Abweichung"})
    )
    print(abweichungen)
    print("Median", abweichungen.median())


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

        Simulation         x         y  im Kreis
0                1  0.248617 -0.899030      True
1                1  0.583638  0.933873     False
2                1 -0.479969 -0.740391      True
3                1 -0.205841  0.750995      True
4                1 -0.569170 -0.763739      True
5                1  0.289227  0.986060     False
6                1 -0.850686  0.466077      True
7                1 -0.007428  0.822337      True
8                1 -0.314241  0.993074     False
9                1 -0.615237  0.744326      True
10               1 -0.595256 -0.310510      True
11               1 -0.743402  0.533695      True
12               1  0.167688  0.900862      True
13               1  0.185315  0.929584      True
14               1  0.737923 -0.711516     False
15               1  0.534371 -0.933298     False
16               1  0.153461 -0.413594      True
17               1  0.142533 -0.659727      True
18               1 -0.697535  0.464171      True
19               1 -0.869226  0.993673     False
20               1 -0.602461 -0.672275      True
21               1  0.724080 -0.071207      True
22               1  0.007867 -0.277731      True
23               1 -0.031231 -0.763030      True
24               1  0.562202  0.653644      True
25               1  0.303479  0.317006      True
26               1  0.636467  0.797304     False
27               1 -0.156960  0.141792      True
28               1  0.120300 -0.101982      True
29               1  0.473958 -0.547495      True
...            ...       ...       ...       ...
449970           9 -0.804482 -0.269954      True
449971           9 -0.343099 -0.631953      True
449972           9  0.641020  0.895462     False
449973           9 -0.601644  0.224732      True
449974           9 -0.011769 -0.737369      True
449975           9 -0.486407  0.003346      True
449976           9 -0.330856  0.480238      True
449977           9  0.357420  0.382098      True
449978           9 -0.562269  0.951690     False
449979           9  0.948544 -0.920091     False
449980           9 -0.900555 -0.301156      True
449981           9  0.268324 -0.052939      True
449982           9 -0.441177 -0.606367      True
449983           9  0.010240 -0.765957      True
449984           9  0.909817 -0.982228     False
449985           9  0.239209 -0.709239      True
449986           9  0.275994  0.709313      True
449987           9 -0.997069  0.647565     False
449988           9  0.579023  0.987883     False
449989           9  0.113928 -0.560803      True
449990           9 -0.502558  0.483353      True
449991           9  0.447500  0.912165     False
449992           9 -0.963741 -0.484180     False
449993           9  0.506204 -0.206595      True
449994           9  0.702868  0.673793      True
449995           9 -0.835202 -0.810745     False
449996           9  0.404636 -0.976605     False
449997           9 -0.069372 -0.650866      True
449998           9 -0.381711 -0.983373     False
449999           9 -0.921674  0.638572     False

[450000 rows x 4 columns]
            Abweichung
Simulation            
1             0.013033
2             0.006713
3             0.009113
4             0.004247
5             0.018647
6             0.000407
7             0.006793
8             0.002953
9             0.011047
Median Abweichung    0.006793
dtype: float64
Grafik:
Bild
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

I like oder Daumen hoch!
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Antworten