Newbie braucht Hilfe bei Laufzeitoptimierung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
PhilipLane
User
Beiträge: 7
Registriert: Freitag 12. Dezember 2014, 11:11

Hallo Leute,

ich bin eigentlich noch ein absoluter Anfänger in der Programmierung und ich arbeite mich nun seit zwei Monaten in Python3 ein.
Ich möchte ein Programm schreiben, das Zufallszahlen x_1 bis x_5 erzeugt, die einer bestimmten Verteilung unterliegen.
beispielsweise ist x_1 dreieckverteilt, x_2 normalverteilt, usw und damit werden dann Zufallszahlen y = f(x_1,...,x_5) berechnet,
wobei f irgendeine Funktion ist. Anschließend sollen die Werte für y in einem Histogramm ausgegeben werden.
Das Programm läuft auch bereits, aber bislang habe ich für f nur die vier Grundrechenarten und Potenzen verwendet.

Nun habe ich ein Problem, wenn ich aus numpy mathematische Funktionen wie cos, sin und exp verwenden will.
Mein Problem besteht darin, dass die Laufzeit bei 3*10**5 Zufallszahlen bis zu 180 Sekunden und teilweise noch länger beträgt.

Hier einmal ein Minimalbeispiel, dass bei mir nach 10 Minuten noch kein Histogramm zum Vorschein bringt.

Code: Alles auswählen

import random
import matplotlib.pyplot as plt
import sympy
import time

Timestamp_1 = time.time()    

Data = [ float(sympy.sin(random.triangular(0, 5, 10)))  for i in range(0, 3*10**5) ]

plt.hist(Data ,bins = 55, color='maroon', normed=True)
plt.title('Error Distribution')
plt.xlabel('x-Achse')
plt.ylabel("Probability")
plt.show()

Timestamp_2 = time.time()

T=round(Timestamp_2 - Timestamp_1,2)
print('Laufzeit:', T)
Ich habe bereits im Internet und hier im Forum ein wenig gesucht und dabei gelesen, dass das random-Modul in Python sehr langsam sein soll, dass es aber hin und wieder
Wege und Möglichkeiten gibt, die Laufzeit zu optimieren. Daher wollte ich einmal fragen, ob das bei meinem Vorhaben auch möglich ist und ob jemand
einen effektiveren Weg sieht, ein solches Histogramm zu erstellen.

Schon einmal vielen lieben Dank im Voraus!
Zuletzt geändert von PhilipLane am Freitag 16. Januar 2015, 17:19, insgesamt 2-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Nimm doch einfach NumPy, das braucht dafür quasi keine Zeit:

Code: Alles auswählen

numpy.random.triangular(0, 5, 10, size=3*10**5)
SymPy ist dafür einfach die falsche Bibliothek, die ist für symbolisches Rechnen gedacht. Das random-Modul an sich ist nicht langsam.

Edit: SciPy in SymPy geändert.
Zuletzt geändert von EyDu am Freitag 16. Januar 2015, 17:29, insgesamt 1-mal geändert.
Das Leben ist wie ein Tennisball.
BlackJack

@EyDu: Pssst, Du hast SciPy geschrieben, meintest aber sicher Sympy. ;-)
PhilipLane
User
Beiträge: 7
Registriert: Freitag 12. Dezember 2014, 11:11

Wow, danke!
Ich wusste nicht, dass Numpy soetwas auch kann!

Code: Alles auswählen

Data = [ float(numpy.sin(numpy.random.triangular(0, 5, 10)))  for i in range(0,10**5)]

plt.hist(Data ,bins = 55, color='maroon', normed=True)
plt.title('Error Distribution')
plt.xlabel('x-Achse')
plt.ylabel("Probability")
plt.show()
Nun benötige ich nur eine Laufzeit von 0.69 Sekunden!
Du hast mir gerade echt den Abend gerettet!
BlackJack

@PhilipLane: Und jetzt verwende mal das was EyDu geschrieben hat, also *wirklich* Numpy verwenden und nicht dann doch wieder eine Liste erstellen und ganz viele unnötige `float()`-Aufrufe machen. ;-)
PhilipLane
User
Beiträge: 7
Registriert: Freitag 12. Dezember 2014, 11:11

Okay, danke.

Ich sehe gerade, dass man bei numpy das float weglassen kann.
Bei sympy musste man es dazuschreiben, weil sonst beim Erstellen des Histogramms ein DataType-Fehler auftrat.
Anscheinend benutzt sympy für Zahlen einen anderen Datentyp als Python selbst und das musste mit float() umgewandelt werden.
Stand zumindest irgendwo bei stack-overflow und hat bei mir auch funktioniert.

Aber um das Erstellen einer Liste komme ich doch nicht herum, oder?

Ich kann ja mit dem Code von EyDu nur eine Liste von dreieckverteilten Zufallszahlen erstellen.
Wenn ich aber ein Histogramm für y = sin( Zufallszahl ) haben möchte, muss ich jede der Zufallszahlen doch verrechnen und zuerst in
eine Liste speichern, die ich dann als Histogramm darstelle. Oder geht das auch irgendwie einfacher?
BlackJack

@PhilipLane: Numpy funktioniert zwar auch mit Einzelwerten aber hauptsächlich ist die Bibliothek zum Rechnen mit Arrays gedacht. Wenn Du ein Numpy-Array hast und etwas mit allen Zahlen in diesem Array machen möchtest, dann wendest Du die entsprechende Operation oder Numpy-Funktion einfach auf das Array an. Also:

Code: Alles auswählen

data = numpy.sin(numpy.random.triangular(0, 5, 10, size=10**5))
PhilipLane
User
Beiträge: 7
Registriert: Freitag 12. Dezember 2014, 11:11

BlackJack hat geschrieben:Wenn Du ein Numpy-Array hast und etwas mit allen Zahlen in diesem Array machen möchtest, dann wendest Du die entsprechende Operation oder Numpy-Funktion einfach auf das Array an.
Das wusste ich nicht, aber ich finde es toll, wie einfach es ist! :D
Ich werde mich dann über das Wochenende mal mit numpy befassen.

Vielen lieben Dank! Ihr habt mir gerade echt aus der Patsche geholfen!

Schönes Wochenende,
Kevin
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

BlackJack hat geschrieben:@EyDu: Pssst, Du hast SciPy geschrieben, meintest aber sicher Sympy. ;-)
Danke, natürlich. Da waren die Hände schneller als das Gehirn.
Das Leben ist wie ein Tennisball.
Antworten