2013-08-06 10 views
10

Mam pytanie koncepcyjne na budowanie histogramu w locie z Python. Próbuję dowiedzieć się, czy istnieje dobry algorytm lub może istniejący pakiet.Symulacja Monte Carlo z pytonem: budowanie histogramu w locie

Napisałem funkcję, która uruchamia symulację Monte Carlo, jest wywoływana 1 000 000 000 razy i zwraca liczbę zmiennoprzecinkową 64-bitową na końcu każdego przebiegu. Poniżej znajduje się wspomniana funkcja:

def MonteCarlo(df,head,span): 
    # Pick initial truck 
    rnd_truck = np.random.randint(0,len(df)) 
    full_length = df['length'][rnd_truck] 
    full_weight = df['gvw'][rnd_truck] 

    # Loop using other random trucks until the bridge is full 
    while True: 
     rnd_truck = np.random.randint(0,len(df)) 
     full_length += head + df['length'][rnd_truck] 
     if full_length > span: 
      break 
     else: 
      full_weight += df['gvw'][rnd_truck] 

    # Return average weight per feet on the bridge 
    return(full_weight/span) 

df jest Pandy dataframe obiekt mający kolumny oznaczone jako 'length' i 'gvw', które są długości i masy pojazdów ciężarowych, odpowiednio. head to odległość między dwiema kolejnymi ciężarówkami, span to długość mostu. Funkcja losowo umieszcza ciężarówki na mostku, o ile całkowita długość pociągu ciężarówki jest mniejsza niż długość mostu. Na koniec oblicza średnią masę ciężarówek istniejących na mostku na stopę (łączna waga istniejąca na pomoście podzielona przez długość mostu).

W rezultacie chciałbym utworzyć histogram tabelaryczny pokazujący rozkład zwróconych wartości, który można później wykreślić. Miałem kilka pomysłów w głowie:

  1. Przechowywać zbierania zwróconych wartości w wektorze numpy, a następnie użyć istniejących funkcji histogramu raz analiza MonteCarlo jest zakończona. Nie byłoby to możliwe, ponieważ jeśli moje obliczenia są poprawne, potrzebowałbym 7,5 GB pamięci tylko dla tego wektora (1 000 000 000 64-bitowe zmienne ~ 7,5 GB).

  2. Inicjalizacja tablicy numpy z podanym zakresem i liczbą pojemników . Zwiększ liczbę przedmiotów w koszu dopasowującym o jeden na końcu każdego przebiegu. Problem polega na tym, że nie znam zakresu wartości, które otrzymam. Ustawienie histogramu z zakresem i odpowiednim rozmiarem bin jest nieznane. Muszę również dowiedzieć się, jak przypisać wartości do właściwych pojemników, ale myślę, że jest to wykonalne.

  3. Czy to jakoś w locie. Zmodyfikuj zakresy i rozmiary bin za każdym razem, gdy funkcja zwróci liczbę. Byłoby to zbyt trudne do napisania od zera, jak sądzę.

Założę się, że może istnieć lepszy sposób na rozwiązanie tego problemu. Wszelkie pomysły byłyby mile widziane!

W drugiej notatce przetestowałem działanie powyższej funkcji 1 000 000 000 razy, aby uzyskać największą wartość, która jest obliczana (fragment kodu jest poniżej). A to zajmie około godziny, gdy span = 200. Czas obliczeń wzrósłby, gdy uruchomię go dla dłuższych rozpiętości (pętla while działa dłużej, aby wypełnić most ciężarówkami). Czy istnieje sposób, aby to zoptymalizować?

max_w = 0 
i = 1 
    while i < 1000000000: 
     if max_w < MonteCarlo(df_basic, 15., 200.): 
      max_w = MonteCarlo(df_basic, 15., 200.) 
    i += 1 
print max_w 

Dzięki!

+0

Przypisywanie wartości do kosza jest po prostu wyszukiwania binarnego. Nie możesz jednak zmienić zasięgu w locie, co oznacza, że ​​musisz znać go z góry lub przechowywać wszystko. Lub przynajmniej wykonaj pewne założenia: np., agreguj dane w małych pojemnikach o danym rozmiarze (dlatego nie musisz przechowywać zbyt dużej ilości danych) i rozwiń listę binów, gdy dane "przepełnią" je. –

+0

@arbautjc dzięki za odpowiedź. Na końcu zredagowałem nieco post związany z problemami z performace, jednak w porównaniu do mojego histogramu ma on niższy priorytet. Miałem trochę nadziei, że może istnieć pakiet naukowy do tego zdolny. – marillion

+0

Daję ci szybką i brudną implementację, używając tabeli mieszania zamiast uporządkowanych list (o wiele prostsze). –

Odpowiedz

2

Oto możliwe rozwiązanie, ze stałym rozmiarem i pojemnikami w formacie [k * rozmiar, (k + 1) * rozmiar [. Funkcja finalizebins zwraca dwie listy: jedną z licznikami bin (a) i drugą (b) z dolnymi granicami bin (górna granica jest wyprowadzana przez dodanie binsize).

import math, random 

def updatebins(bins, binsize, x): 
    i = math.floor(x/binsize) 
    if i in bins: 
     bins[i] += 1 
    else: 
     bins[i] = 1 

def finalizebins(bins, binsize): 
    imin = min(bins.keys()) 
    imax = max(bins.keys()) 
    a = [0] * (imax - imin + 1) 
    b = [binsize * k for k in range(imin, imax + 1)] 
    for i in range(imin, imax + 1): 
     if i in bins: 
      a[i - imin] = bins[i] 
    return a, b 

# A test with a mixture of gaussian distributions 

def check(n): 
    bins = {} 
    binsize = 5.0 
    for i in range(n): 
     if random.random() > 0.5: 
      x = random.gauss(100, 50) 
     else: 
      x = random.gauss(-200, 150) 
     updatebins(bins, binsize, x) 
    return finalizebins(bins, binsize) 

a, b = check(10000) 

# This must be 10000 
sum(a) 

# Plot the data 
from matplotlib.pyplot import * 
bar(b,a) 
show() 

enter image description here