Verdreifachung einer Zufallszahl

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.
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

ich würde gerne mit random so lange eine Zahl von 0 bis 20 generieren, bis zum ersten mal eine der Zahlen zum drittenmal erscheint, und die unterschiedliche Dauer festhalten;

zahlen=[]
for i in range (?):
zahlen.append(random.randint(0,20))


z.B.: 1, 3, 20, 13, 3, 17, 9, 6, 12, 3

bei der 10. Zahl fand zum ersten mal eine Verdreifachung statt, (die "3")

sicher einfach, nicht böse sein, ich bin kein Schüler und auch kein Student, vielleicht hilft mir ja trotzdem jemand von Euch weiter ...
(ich tüftel schon ein paar Tage herum und komm nicht drauf, meine diversen Versuche will ich Euch hier aber ersparen)
__deets__
User
Beiträge: 14525
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dafür bietet sich collections.Counter an, damit kannst du das Vorkommen jeder Zahl nachhalten. Das ist effizienter als jedes Mal die Anzahl der gezogenen Zahl neu zu bestimmen.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@haeuslermartin: Und da Du a) vorher nicht weisst wie oft Du ”würfeln” musst und b) `i` überhaupt nicht verwendet wird, nimmt man hier weder `range()` noch ``for``, sondern eine ``while True``-”Endlos”schleife die man mit ``break`` abbricht wenn die gewünschte Bedingung eingetroffen ist.

Wenn man eine ``for``-Schleife verwenden möchte, kann man sich beispielsweise eine über einen Iterator schreiben der endlos Zufallszahlen liefert (mit `repeatfunc()` aus `more_itertools`):

Code: Alles auswählen

for random_number in repeatfunc(randint, None, 0, 20):
    # Do something with random number.
    if end_condition_reached:
        break
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

Das ist doch eine nette Übungsaufgabe, bei der man gut einige interessante Konstrukte von Python ausprobieren kann :) Einer von mehreren Lösungsansätzen ist zum Beispiel folgender:

Code: Alles auswählen

In [1]: from random import randint                                                                                                                            

In [2]: from statistics import mean, stdev                                                                                                                    

In [3]: def get_random_repetitions(lower=0, upper=20, repetitions=3): 
   ...:     counts = {i: [] for i in range(lower, upper + 1)} 
   ...:     i = 1 
   ...:     while any(len(value) < 3 for value in counts.values()): 
   ...:         number = randint(lower, upper) 
   ...:         counts[number].append(i) 
   ...:         i += 1 
   ...:     return counts 
   ...:                                                                                                                                                       

In [4]: counts = get_random_repetitions()                                                                                                                     

In [5]: relative_durations = []                                                                                                                               

In [6]: for key, value in sorted(counts.items()): 
   ...:     relative_duration = value[2] - value[0] 
   ...:     print('Number: {} relative duration: {} absolute duration {}'.format( 
   ...:     key, relative_duration, value[2])) 
   ...:     relative_durations.append(relative_duration) 
   ...:                                                                                                                                                       
Number: 0 relative duration: 28 absolute duration 53
Number: 1 relative duration: 108 absolute duration 131
Number: 2 relative duration: 72 absolute duration 113
Number: 3 relative duration: 30 absolute duration 52
Number: 4 relative duration: 37 absolute duration 38
Number: 5 relative duration: 28 absolute duration 48
Number: 6 relative duration: 19 absolute duration 73
Number: 7 relative duration: 60 absolute duration 126
Number: 8 relative duration: 9 absolute duration 17
Number: 9 relative duration: 15 absolute duration 30
Number: 10 relative duration: 123 absolute duration 169
Number: 11 relative duration: 18 absolute duration 39
Number: 12 relative duration: 78 absolute duration 110
Number: 13 relative duration: 8 absolute duration 11
Number: 14 relative duration: 53 absolute duration 59
Number: 15 relative duration: 24 absolute duration 55
Number: 16 relative duration: 81 absolute duration 97
Number: 17 relative duration: 40 absolute duration 49
Number: 18 relative duration: 36 absolute duration 69
Number: 19 relative duration: 26 absolute duration 28
Number: 20 relative duration: 14 absolute duration 19

In [7]: print('Mean relative duration: {:.3f} (sd={:.3f})'.format(mean(relative_durations), stdev(relative_durations)))                                       
Mean relative duration: 43.190 (sd=32.476)

In [8]: print('Total repetitions:', max(j for i in counts.values() for j in i))                                                                                
Total repetitions: 169

haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

dankeschön, werde das mal alles probieren, muß mich noch ein wenig schlau machen, mit statistics hatte ich noch nichts zu tun. Der tiefere Sinn des beabsichtigten Codes ist herauszufinden, wie oft man im Schnitt bei einer bestimmten Zahl von Möglichkeiten (20 in meinem Beispiel) "würfeln" muß, bis exakt der erste Drilling erscheint. Mathematisch geht das ja mit der Binomialfunktion, aber das ist sehr abstrakt und ich bin kein Mathematiker, und ausserdem will ich es rein aus Spaß an der Sache empirisch mit einem kleinen Programm versuchen ...
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

hallo, vielleicht darf ich Euch nochmal belästigen, ich komm nicht weiter, das Problem ist ja nicht so sehr die Erzeugung der random - Zahlen, als vielmehr das Feststellen der Position der ersten Verdreifachung einer Zahl.
liste.count(i) zählt ja immer die ganze Liste durch und da bekommt die dreifache Zahl schon beim ersten Erscheinen den Wert "3" zugeordnet. wenn ich das aber ganz normal "menschlich" betrachte, dann sehe ich doch auch nicht schon der Zahl an, dass sie noch zweimal irgendwann erscheint, sondern stelle fest: aha, jetzt kommt sie zum 3. mal. Es doch eine relativ einfache Zählmethode geben, die das so macht wie jeder normale Mensch ...
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@haeuslermartin: Wenn Du das wirklich mit einer Liste und `count()` machst, was recht ineffizient ist, dann hast Du die Position doch durch die Länge der Liste. Denn wenn Du das erste mal feststellst, das die Zufallszahl die Du gerade gezogen hast, bereits zweimal in der Liste ist, dann weisst Du doch das Du das ``len(liste)`` die Anzahl der vorherigen Würfelvorgänge ist.

Falls Du einen `collections.Counter` oder ein Wörterbuch mit 0en intialisiert zum zählen für die einzelnen Werte nimmst, kannst Du entweder Anzahlen aufaddieren wenn Du das erste mal das dritte mal einen Wert gezogen hast, oder Du zählst halt ganz profan mit jedes mal wenn Du `randint()` aufrufst. Falls Du Dir ein iterierbares Objekt über die Zufallszahlen bastelst, kannst Du dafür `enumerate()` verwenden. Ansonsten eben ”manuell” eine Zählvariable erhöhen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

danke, ich dachte mir die Ziehung der Zahlen kann ich mir vereinfachen, indem ich eine Liste mit Zahlen mache, die ausreichend lang ist, so daß mit Sicherheit Verdreifachungen dabei sind, in meinem Beispiel etwa
Zahlen=[random.randint(0,20) for i in range(100)]
und anschließend einfach die erste (und nur um die geht es) Verdreifachung festzustellen, -in diesem Fall gehts natürlich nicht mit len(liste)
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@haeuslermartin: Das Problem dabei ist ja das es keine endliche Liste gibt die ausreichend lang ist, so dass mit *Sicherheit* ein 3fach-Vorkommen von irgend einer Zahl dabei ist. Wobei: Wenn man `random.randint()` nimmt, hat man einen „Mersenne Twister“ mit einer Periode von 2**19937-1 – eine längere Liste braucht man also nicht. 😎

Die Liste brauchst Du doch aber gar nicht – Du brauchst nur eine Liste mit 21 Einträgen um für 0 bis 20 mitzählen zu können wie oft die jeweilige Zahl dran war. Und wenn Du dabei das erste mal auf 3 kommst, zählst Du alle Zähler zusammen und kennst die Position.

Code: Alles auswählen

#!/usr/bin/env python3
from random import randint


def main():
    upper_limit = 20
    counts = [0] * (upper_limit + 1)
    while True:
        number = randint(0, upper_limit)
        counts[number] += 1
        if counts[number] == 3:
            break
    print(sum(counts))



if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

hallo blackjack,
ich habe eine Liste dazugemacht, um das Ergebnis überprüfen zu können:

from random import randint

nummer=[]
def main():
upper_limit = 20
counts = [0] * (upper_limit + 1)
while True:
number = randint(0, upper_limit)
nummer.append(number)
counts[number] += 1
if counts[number] == 3:
break
print(sum(counts))

if __name__ == "__main__":
main()

print("das sind ", len(nummer), " Zahlen ", nummer)

gibt folgenden output:
1
2
3
4
5
6
7
8
9

das sind 10 Zahlen: [0 ,7, 15, 16 ,0, 1, 1, 14, 4, 1]

man sieht, es ist der zehnte Wert, bei dem sich der erste Drilling manifestiert, ich muß also immer einen dazu addieren, -(sum(counts)) endet ja bei 9-, sehe ich das das richtig?
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@haeuslermartin: Das siehst Du falsch, denn Dein Code hat eine andere Einrückung als meiner. *Nach* der Schleife ist die Summe von `counts` 10, aber Du gibst das ja *in* der Schleife aus und zwar nach der Prüfung der Abbruchbedingung. Das heisst das Ergebnis am Ende gibst Du gar nicht aus.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

hallo, danke für die schnelle Antwort, also, ich habe Deinen Code mit seinen Einrückungen nicht verändert, nur eine externe Liste vorneweg und dann mit den Zahlen aufgefüllt, da bin ich jetzt überfordert... das Egebnis "10" wäre das richtige, wie man an der Zahlenreihe "manuell" ja erkennen kann, und allein um das gehts mir ja, als muß es doch gehen, wenn ich einfach eins addiere, es ist ja dann die letzte Position, 9 wäre falsch ... ich meine die 10 Zahlen sind ja einwandfrei die, die mit randit generiert wurden, und da ist einwandfrei auf Position 9 die Zahl 4, die noch nicht der Drilling ist, erst auf der letzten Position kommt zum dritten mal die 1, das Programm macht das alles soweit richtig...
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@haeuslermartin: Du hast in Deinem Skript einen Einrückfehler. Den sehen wir hier nicht, da Dein Code nicht korrekt formatiert ist. Richtig eingerückt funktioniert dagegen alles einwandfrei:

Code: Alles auswählen

from random import randint

def main():
    numbers = []
    upper_limit = 20
    counts = [0] * (upper_limit + 1)
    while True:
        number = randint(0, upper_limit)
        numbers.append(number)
        counts[number] += 1
        if counts[number] == 3:
            break
    print(numbers)
    print(len(numbers))
    print(sum(counts))

if __name__ == "__main__":
    main()
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@kbr: der Code von haeuslermartin hat keinen Einrückfehler, aber zu diesem Code passt auch nicht die Ausgabe.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Sirius3: wenn 'print(sum(counts))' durch Einrückung Bestandteil der Schleife ist, dann passt die Ausgabe zum Code. Einrückfehler müssen nicht immer zu Syntaxfehlern führen.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@kbr: Ich denke Sirius3 meint den Code den haeuslermartin hier im Forum gezeigt hat. Die dortige Einrückung entspricht der von mir, passt aber nicht zu der Ausgabe die in dem Beitrag steht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@__blackjack__: das mag sein, auch wenn ich in dem Beitrag optisch keine Einrückungen erkennen kann. Wenn die Einrückungen aber richtig sind, warum dann unpassenden output posten? Davon war ich nicht ausgegangen.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@kbr: im HTML-Source sieht man die Einrückungen. Und mich wundert ja auch, warum Code und Output nicht zusammenpassen.
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

also Leute, ich danke Euch herzlich, ich bin weder Student noch Schüler und auch auch kein Programmierer, ich will mit meinen 68 Jahren auch kein Python Experte mehr werden, mein Steckenpferd ist der Zufall, das "Gesetz der kleinen Zahl", das Gesetz der kleinen Zahl, weil alles was im Unendlichen passiert für das menschliche Erleben irrelevant ist. Und da macht es mir Spaß, mit einigen wenigen Anfängerkenntnissen was zu schreiben, womit ich empirisch Fragen beantworten kann, -wie z.B. wie oft kommt es vor, dass beim Münzwurf 30 mal hintereinander "Zahl" fällt. Würde das Gesetz der großen Zahl, wonach jeder Münzwurf die gleiche Wahrscheinlichkweit hat totalitär greifen, müsste dies oft der Fall sein. Wie es mir scheint, sind beide Betrachtungsweisen legitim, führen quasi eine Art Koexistenz der Wahrheiten, eine fortlaufend endliche, - und eine ohne Anfang und Ende. Was versteht man unter "an Sicherheit grenzender Wahscheinlichkeit"? Doch nahezu alles was uns im Leben wiederfährt, ist dem Zufall unterworfen. Zufall - Gott - Schicksal ??
Nochmals Dankeschön.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@haeuslermartin: Wie oft ist oft und wie oft wird denn 30 mal hintereinander die Münze geworfen? Wenn ich eine Münze 30 mal Werfe, dann besteht eine Chance von 1 zu 1.073.741.824 das alle 30 mal Zahl dabei herum kommt. Das könnte eine Weile dauern bis man das mal erlebt *also* *einmal*. Wieso meinst Du das müsste ”oft” der Fall sein?

Wenn man davon ausgeht das alles den Naturgesetzen unterliegt und man aus jedem Zustand des Universums auch jeden Folgezustand berechnen kann, wenn man denn nur alle Variablen und genug Zeit hätte das zu machen bevor es tatsächlich eingetreten ist, dann ist nichts dem Zufall unterworfen. 😉
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten