2017-03-01 19 views
2

Ich versuche meinen Code zu verbessern, der zufällig generierte Zahlen in Entfernungsintervalle sortiert, um die Genauigkeit des Zufallszahlengenerators zu analysieren. Momentan wird meine Sortierung von 20 Elif-Anweisungen durchgeführt (ich habe nur ein Einführungswissen über Python) und daher dauert die Ausführung meines Codes sehr lange. Wie kann ich numerische Daten effizienter in Intervalle sortieren und nur die Häufigkeit von Zahlen im Intervall speichern?Zählfrequenzen numerischer Daten in Intervallintervallen

from datetime import datetime 
startTime = datetime.now() 
def test_rand(points): 
    import random 
    d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17,d18,d19,d20 = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 
    # these variables will be used to count frequency of numbers into 20 intervals: (-10,-9], (-9,-8] ... etc 
    g1,g2,g3,g4,g5,g6,g7,g8,g9,g10,g11,g12,g13,g14,g15,g16,g17,g18,g19,g20 = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 
    # these variables will be used to count frequency of every 20 numbers into 20 intervals: (-200,-180], (-180,-160] ... etc 
    y = 0 
    n = 0 
    for i in range(points): 
     x = random.uniform(-10.0,10.0) 
     while n < 20: 
      y += x 
      n += 1 
      break 
     if n == 20: 
      if y < -180: 
       g1 += 1 
      elif y < -160 and y > -180: 
       g2 += 1 
      elif y < -140 and y > -160: 
       g3 += 1 
      elif y < -120 and y > -140: 
       g4 += 1 
      elif y < -100 and y > -120: 
       g5 += 1 
      elif y < -80 and y > -100: 
       g6 += 1 
      elif y < -60 and y > -80: 
       g7 += 1 
      elif y < -40 and y > -60: 
       g8 += 1 
      elif y < -20 and y > -40: 
       g9 += 1 
      elif y < 0 and y > -20: 
       g10 += 1 
      elif y < 20 and y > 0: 
       g11 += 1 
      elif y < 40 and y > 20: 
       g12 += 1 
      elif y < 60 and y > 40: 
       g13 += 1 
      elif y < 80 and y > 60: 
       g14 += 1 
      elif y < 100 and y > 80: 
       g15 += 1 
      elif y < 120 and y > 100: 
       g16 += 1 
      elif y < 140 and y > 120: 
       g17 += 1 
      elif y < 160 and y > 140: 
       g18 += 1 
      elif y < 180 and y > 160: 
       g19 += 1 
      elif y > 180: 
       g20 += 1 
      y *= 0 
      n *= 0 

     if x < -9: 
      d1 += 1 
     elif x < -8 and x > -9: 
      d2 += 1 
     elif x < -7 and x > -8: 
      d3 += 1 
     elif x < -6 and x > -7: 
      d4 += 1 
     elif x < -5 and x > -6: 
      d5 += 1 
     elif x < -4 and x > -5: 
      d6 += 1 
     elif x < -3 and x > -4: 
      d7 += 1 
     elif x < -2 and x > -3: 
      d8 += 1 
     elif x < -1 and x > -2: 
      d9 += 1 
     elif x < 0 and x > -1: 
      d10 += 1 
     elif x < 1 and x > 0: 
      d11 += 1 
     elif x < 2 and x > 1: 
      d12 += 1 
     elif x < 3 and x > 2: 
      d13 += 1 
     elif x < 4 and x > 3: 
      d14 += 1 
     elif x < 5 and x > 4: 
      d15 += 1 
     elif x < 6 and x > 5: 
      d16 += 1 
     elif x < 7 and x > 6: 
      d17 += 1 
     elif x < 8 and x > 7: 
      d18 += 1 
     elif x < 9 and x > 8: 
      d19 += 1 
     elif x > 9: 
      d20 += 1 

    return d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16,d17,d18,d19,d20,g1,g2,g3,g4,g5,g6,g7,g8,g9,g10,g11,g12,g13,g14,g15,g16,g17,g18,g19,g20 

print(test_rand(100000000))  

print (datetime.now() - startTime) 

Der Code soll 2 Funktionen mit den Zufallszahlen ausführen. Die erste besteht darin, die Zahlen in 20 Intervalle zu sortieren (also sollten 5% der Zahlen in jedem Intervall liegen). Das zweite ist, alle 20 Zahlen erzeugt zusammenzufassen und legen diese in 20 neue Intervalle Code für die Durchführung der oben (eine normale Kurve zu beachten)

@tristan Ich habe geändert:

for idx in range(points): 
     val_1 = uniform(-10, 10) 
     val_20 += val_1 
     if (idx + 1) % 20 == 0: 
      counter2[bisect(occ2, val_20)] += 1 
      counter1[bisect(occ1, val_1)] += 1 
      val_20 = 0 
      val_1 = 0 
     else: 
      counter1[bisect(occ1, val_1)] += 1 
      val_1 = 0 

Während dieser Methode spart nur 6 Sekunden (1:54 -> 1:48) es ist FAR besser organisiert und leichter zu sehen. Danke für die Hilfe!

+0

Verwenden Sie stattdessen zwei Listen. Ich sehe den Punkt der while-Schleife nicht. Verwenden Sie etwas Mathematik, um den Index zu berechnen. –

Antwort

2

Unter der Annahme, dass die Daten immer an einem Ihrem Intervall zugeordnet werden (man könnte Check vor), mit bisect.bisect() würde eine effiziente und kompakte Art und Weise sein:

from bisect import bisect 
from random import randint 

occ1 = [-9 + 1 * i for i in range(19)] 
occ2 = [-180 + 20 * i for i in range(19)] 
data = [randint(-10, 10) for _ in range(100)] 
counter1, counter2 = {i: 0 for i in range(20)}, {i: 0 for i in range(20)} 

for idx, element in enumerate(data): 
    if (idx + 1) % 20 == 0: 
     counter2[bisect(occ2, element)] += 1 
    else: 
     counter1[bisect(occ1, element)] += 1 

Die bisect () Funktion gibt die Position zurück, wo das Element in ein geordnetes Array wie occ eingefügt werden sollte, um die Bestellung aufrechtzuerhalten. Bei 19 Werten in occ gibt es 20 verschiedene Positionen, an denen ein Wert eingefügt werden kann. Das heißt, vor dem ersten, zwischen irgendeinem der Elemente oder nach dem letzten. Dies entspricht Ihren 20 Intervallen. Das einzige, worüber man sich Gedanken machen sollte, ist e. G. Ist ein Element kleiner oder größer als die obere oder untere Grenze Ihrer Intervalle, wird es immer noch dem niedrigsten oder höchsten Intervall zugewiesen. Das Erzeugen von Zufallszahlen, die die Intervallgrenzen berücksichtigen, würde dies jedoch verhindern.

Von Ihrer Frage bin ich nicht sicher, ob Sie einige Zufallszahlen kumulieren oder nur die Liste der Punkte überprüfen möchten, wo alle 20 Werte eine andere Überprüfung durchgeführt wird. Die Lösung leicht Zufallszahl angepasst werden könnte, kumulieren bis 20 Iterationen erreicht:

from bisect import bisect 
from random import uniform 

points, value = 100000000, 0 
occ1 = [-9 + 1 * i for i in range(19)] 
occ2 = [-180 + 20 * i for i in range(19)] 
counter1, counter2 = {i: 0 for i in range(20)}, {i: 0 for i in range(20)} 

for idx in range(points): 
    value += uniform(-10, 10) 
    if (idx + 1) % 20 == 0: 
     counter2[bisect(occ2, value)] += 1 
     value = 0 
    else: 
     counter1[bisect(occ1, value)] += 1 

Dies läuft in 100 Sekunden für 100M Punkte auf meinem Rechner.

+0

@qwop Passt das zu dem, was Sie tun wollten? – Tristan

+0

Danke für die Erklärung der Bisektionsfunktion. Ich denke, dass ich diesen Code für das Addieren der Zufallszahlen korrekt ändern konnte – qwop

Verwandte Themen