Zufallszahlen in Liste schreiben

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
Benutzeravatar
Kurtosis
User
Beiträge: 55
Registriert: Samstag 11. Dezember 2010, 14:32

Hallo,

ich versuche ein Programm zu schreiben, um nach dem Maximum-Likelihood-Verfahren einen Parameter zu schätzen (hier soll es der Mittelwert einer normalverteilten Größe sein). Das Programm möchte ich möglichst flexibel und elegant schreiben. Am Anfang möchte ich gefragt werden, wie viele Stichproben genommen werden sollen. Als Anwendungsbeispiel habe ich eine Getränkeabfüllanlage im Kopf. Wähle ich n Stichproben, generiert mir das Programm n Zufallswerte, die um beispielsweise 0,5 verteilt sind. Idee war nun, dass mir das Programm n Stichprobenwerte in eine Liste schreibt, mit der ich dann im weiteren Verlauf des Programms weiterarbeite. Problem: Im Moment schaffe ich es nicht, die Zufallszahlen in eine Liste schreiben zu lassen. Ich hab mir überlegt, dass ich mit einer for-Schleife arbeite, die mir nach jedem Durchlauf den jeweils generierten Wert in eine zunächst leere Liste schreibt.
Vielleicht hat hier jemand hilfreiche Tipps oder Programmbeispiele.

Danke schon mal!

Anmerkung:
Wie ich mir das vorstelle, wenn beispielsweise 3 Stichproben genommen werden:
Durchlauf 0: liste = []
Durchlauf 1: Stichprobe 490 wurde generiert --> liste = [490]
Durchlauf 2: Stichprobe 510 wurde generiert --> liste = [490, 510]
Durchlauf 3: Stichprobe 500 wurde generiert --> liste = [490, 510, 500]
BlackJack

@Kurtosis: Warum machst Du das was Du Dir überlegt hast nicht einfach mal? Das ist doch schneller als hier zu fragen.

Statt einer Schleife die eine leere Liste befüllt, könnte man eine „list comprehension” verwenden.
Benutzeravatar
Kurtosis
User
Beiträge: 55
Registriert: Samstag 11. Dezember 2010, 14:32

Ich probiere auch die ganze Zeit schon daran rum, aber bisher es hat es noch nicht geklappt. Bin gerade aber einen großen Schritt weiter gekommen. Wenn ich das gewünschte Ergebnis erzielt habe, poste ich mal, was ich da programmiert habe, falls da Interesse besteht.
Benutzeravatar
Kurtosis
User
Beiträge: 55
Registriert: Samstag 11. Dezember 2010, 14:32

Hab es hingekriegt.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@Kurtosis: Und wie?
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
Kurtosis
User
Beiträge: 55
Registriert: Samstag 11. Dezember 2010, 14:32

So, Programm ist nun fertig und berechnet Mittelwert, Varianz und Standardabweichung der Stichproben, ohne dabei vorgefertigte Funktionen, die direkt den Mittelwert berechnen würden, zu verwenden. Das Problem im Eingangsposting habe ich wie folgt gelöst:

Code: Alles auswählen

liste1 = list()
def Stichproben(n):
	for i in range(0,n):
		a = random.randint(490,510)
		b = liste1.append(a)
Zuletzt geändert von Kurtosis am Dienstag 2. Juli 2013, 15:16, insgesamt 4-mal geändert.
BlackJack

@Kurtosis: Die Funktion führt zu einem `NameError` weil `liste1` nicht definiert ist. Wobei ich mich auch Frage was die 1 in dem Namen zu suchen hat, denn es gibt in der Funktion ja nur eine Liste (wenn man sie denn mal definieren würde) und Namen durchnummerieren ist in der aller Regel sowieso ein Zeichen, dass man etwas falsch macht. Entweder schlechte Namen oder falsche Datenstruktur.

`b` macht keinen Sinn weil der Wert 1. sinnlos ist und 2. überhaupt nicht verwendet wird.
Benutzeravatar
Kurtosis
User
Beiträge: 55
Registriert: Samstag 11. Dezember 2010, 14:32

Hab oben noch ein paar Verbesserungen vorgenommen. Ich probiere ja noch rum, deswegen mag die erste Version vielleicht noch nicht super elegant sein. Tatsache ist aber, dass das Programm macht, was es tun soll, und mir grundsätzlich klar ist, was in welcher Zeile passiert. Das die eine oder andere Programmzeile noch nicht optimal ist, mag sein.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Kurtosis hat geschrieben:

Code: Alles auswählen

liste1 = list()
def Stichproben(n):
	for i in range(0,n):
		a = random.randint(490,510)
		b = liste1.append(a)
	return liste1
Das ist ein sehr ausführlicher (und umständlicher Code). Zudem sollte man liste1 innerhalb der Funktion definieren, abgesehen davon, dass es meist eher sinnlos/unklug ist, den Datentyp direkt im Bezeichnernamen anzugeben.

Unter Verwendung einer List Comprehension lässt sich der ganze Code wie folgt eindampfen:

Code: Alles auswählen

def strichproben(n):
   return [random.randint(490, 510) for _ in xrange(n)]
Für Python 3 bitte xrange durch range ersetzen.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@Kurtosis: Naja. Daran gibt es einiges zu verbessern. Warum ist liste1 keine lokale Variable der Funktion Stichproben()?

Code: Alles auswählen

def Stichproben(n):
   liste1 = list()
   for i in range(1, n + 1):
      a = random.randint(490, 510)
      b = liste1.append(a)
   return liste1
Man könnte übrigens einfach [] statt list() schreiben:

Code: Alles auswählen

def Stichproben(n):
   liste1 = []
   for i in range(1, n + 1):
      a = random.randint(490, 510)
      liste1.append(a)
   return liste1
b ist immer None, da die Listenmethode append() eben immer None zurückgibt. Also:

Code: Alles auswählen

def Stichproben(n):
   liste1 = []
   for i in range(1, n + 1):
      a = random.randint(490, 510)
      liste1.append(a)
   return liste1
Die Variable a braucht man eigentlich auch nicht:

Code: Alles auswählen

def Stichproben(n):
   liste1 = []
   for i in range(1, n + 1):
      liste1.append(random.randint(490, 510))
   return liste1
Der Abstand von 1 zu n + 1 ist derselbe wie von 0 zu n. Die range()-Funktion startet immer bei 0, falls kein anderer Startwert angegeben wird:

Code: Alles auswählen

def Stichproben(n):
   liste1 = []
   for i in range(n):
      liste1.append(random.randint(490, 510))
   return liste1
Nun kann man aus der for-Schleife auch eine List Comprehension machen:

Code: Alles auswählen

def Stichproben(n):
   liste1 = [random.randint(490, 510) for i in range(n)]
   return liste1
Damit brauchen wir auch liste1 nicht mehr:

Code: Alles auswählen

def Stichproben(n):
   return [random.randint(490, 510) for i in range(n)]
Nun würde ich noch vorschlagen, sich an PEP8 zu halten und den Funktionsnamen klein zu schreiben, oder sogar die Funktion einfach wegzulassen und die List Comprehension direkt zu verwenden. Als statt etwa:

Code: Alles auswählen

result = Stichproben(some_number)
zu schreiben:

Code: Alles auswählen

result = [random.randint(490, 510) for i in range(some_number)]
. Und falls du Python 2.x verwendest, würde ich hier statt range() die Funktion xrange() verwenden:

Code: Alles auswählen

result = [random.randint(490, 510) for i in xrange(some_number)]
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
Kurtosis
User
Beiträge: 55
Registriert: Samstag 11. Dezember 2010, 14:32

Danke euch! Ich werde mir eure Anmerkungen mal klarmachen und dann entsprechend berücksichtigen. Da Programmierung kein elementarer Bestandteil meines Studiums ist und ich mich aus Zeitgründen nicht jeden Tag damit beschäftigen kann, bin ich halt noch ein Python-Amateur. Mein Code mag vielleicht umständlich sein, aber ich verstehe so leichter, was im Programm eigentlich passiert, da halt nicht mehrere Sachen gleichzeitig in einer Zeile passieren. Aber danke für eure Tipps!
Benutzeravatar
Kurtosis
User
Beiträge: 55
Registriert: Samstag 11. Dezember 2010, 14:32

Ich habe jetzt noch ein paar Verbesserungen vorgenommen.

Code: Alles auswählen

# Zusatzpakete
import random

# Funktionen
def start():
	print "########################################"
	print "###   Maximum-Likelihood-Verfahren   ###"
	print "###         Normalverteilung         ###"
	print "########################################"
	print ""

def anfangsbedingungen():
	print "Wie groß ist der Umfang der Stichproben?"
	n = input("Umfang der Stichproben: ")
	print "Welchen Wert hätte die optimale Stichprobe?"
	mu = input("Optimale Stichprobe: ")
	sigma = random.uniform(0,0.02*mu)
	return n,mu,sigma

def stichproben(n,mu,sigma):
	return [round(random.normalvariate(mu,sigma),2) for i in xrange(n)]

def stichprobenprotokoll(liste1):
	print ""
	print "Stichprobenprotokoll:"
	print liste1

def mittelwert(liste1,n):
	summe = sum(liste1)
	mittelwert = round(summe*1./n,2)
	print ""
	print "Mittelwert der Stichproben:", mittelwert
	return mittelwert

def varianz(liste1,mittelwert,n):
	liste2 = [(liste1[i] - mittelwert)**2 for i in xrange(n)]
	varianz = round(sum(liste2)*1./n,2)
	standardabweichung = round((sum(liste2)*1./n)**(1./2),2)
	print "Varianz der Stichproben:", varianz
	print "Standardabweichung der Stichproben:", standardabweichung

# Programm
start()
n,mu,sigma = anfangsbedingungen()
liste1 = stichproben(n,mu,sigma)
stichprobenprotokoll(liste1)
mittelwert = mittelwert(liste1,n)
varianz(liste1,mittelwert,n)
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Kurtosis: den Mittelwert zu runden und dann damit weiterzurechnen ist vielleicht nicht die beste Idee. Wenn es Dir nur darum geht, die Ausgabe schön zu haben, bieten sich Formatierungen an:

Code: Alles auswählen

print "Mittelwert: {:.2f}".format(mittelwert)
In »varianz« die Summe zweimal auszurechnen ist dann auch unnötig. Die Anzahl der Elemente weißt Du schon aus der Länge der Liste, muß also nicht extra mitgegeben werden. For-Schleifen in Python gehen über alle Elemente einer Liste. Wenn Du also eine for-Schleife über alle Indizes einer Liste machst um danach die Listenelemente über den Index anzusprechen drehst Du Dich wieder dreimal im Kreis:

Code: Alles auswählen

def varianz(liste1, mittelwert):
        varianz = sum((wert - mittelwert)**2 for wert in liste1)/float(len(liste1))
        standardabweichung = varianz**0.5
        print "Varianz der Stichproben: {:.2f}".format(varianz)
        print "Standardabweichung der Stichproben: {:.2f}".format(standardabweichung)
Benutzeravatar
Kurtosis
User
Beiträge: 55
Registriert: Samstag 11. Dezember 2010, 14:32

@Sirius3: Danke, hab den Code entsprechend angepasst und verbessert.
georgebaker
User
Beiträge: 25
Registriert: Freitag 12. April 2013, 19:53

@Kurtosis:

Wenn ich mir dein Programm anschaue erzeugst du nur Zahlen im Bereich +/- Sigma um den Mittelwert. Das entspricht aber nur 68,27% aller Stichproben bei einer Normalverteilung. Ohne jetzt deinen Verwendungszweck genau zu kennen, müsste die Verteilung eigentlich von - unendlich bis + unendlich stattfinden.
Antworten