2011-04-25 83 views
2

Une simulation de base de GBM ne semble pas fonctionner. Qu'est-ce que je fais mal? Le code suivant renvoie toujours des valeurs inférieures à 1E-20, au lieu de quelque chose distribués de façon aléatoire autour de 1.0:python: simulation de mouvement brownien géométrique

import math 
import random 

p = 1 
dt = 1 
mu = 0 
sigma = 1 
for k in range(100): 
    p *= math.exp((mu - sigma * sigma/2) * dt + 
     sigma * random.normalvariate(0, dt * dt)) 
print(p) 

Je suis en cours d'exécution:

ActivePython 3.1.2.3 (ActiveState Software Inc.) basée sur Python 3.1.2 (r312: 79147, 22 mars 2010, 12:30:45) [MSC v.1500 64 bits (AMD64)] sur win32

Mon système d'exploitation est Windows 7 Professionnel sur le processeur i7-930 (64- bit).

Je serais heureux d'exécuter d'autres tests sur ma machine pour isoler le problème.

+0

Quelle version de Python utilisez-vous? Certaines informations sur la machine seraient utiles. Format – Blender

Répondre

3

J'ai trouvé la réponse. Il n'y a pas de problème avec le code. C'est juste que la distribution lognormale résultante a un paramètre d'échelle énorme = 1 * sqrt (100) = 10. Avec une échelle de 10, l'asymétrie est folle.

Ainsi, même si la moyenne de la distribution est 1.0, il me faudra des milliards d'itérations (sinon milliards de milliards) pour voir un seul nombre supérieur à 1.0.

0

Semble bien:

import math 
import random 

def compute(): 
    p = 1 
    dt = 1 
    mu = 0 
    sigma = 1 
    for k in range(100): 
     p *= math.exp((mu - sigma * sigma/2) * dt + 
         sigma * random.normalvariate(0, dt * dt)) 
    return p 

print [compute() for x in range(20)] 

donne:

[118.85952235362008, 7.3312246638859059e-14, 29.509674994408684, 1.8720575806397408, 1.5882398997219834e-05, 2967.524471541024, 0.0031130343677571093, 19942.669293314699, 0.00011878818261757498, 5382.80288111769, 0.22867624175360118, 0.028535167622775418, 12.6324011631628, 20.604456159054738, 0.0034504567371058613, 6.5804828930878056e-06, 6398.0493448486704, 0.0014978345496292245, 721546.38343724841, 1285.546939393781] 

Ce utilise python 2.6.1

+0

yer code, s'il vous plaît ... – Blender

+0

En utilisant ActiveState Python 3.1.2.3 sur Windows 7 x64, je deviens: 2.88084588316e-26 1.79846330571e-29 5.33216495039e-16 3.65633773649e-24 1.4585366594e-20 5.89100557394e-29 6.54803262332e-22 6.4358184422e-26 5.84172579131e-16 1.54534837363e-20 1.80941931541e-21 1.1932380739e-19-2.05849658827e 19 2.72778662212e-26 5.76789574386e-11 1.28691566317e-20 2.0417208905e-17 1.0618463823 8e-28 8.75599425267e-26 9.76030276598e-24 – max

0

L'exécution du code en Python 2.6.6 obtient des réponses raisonnables, alors qu'il en cours d'exécution Python 3.1.2 donne les petits nombres que vous décrivez. Je pense que c'est parce que dans Python 2.x l'opérateur de division donne un résultat entier en divisant deux entiers, alors qu'en Python 3.x il donne un résultat à virgule flottante dans la même situation. Par conséquent, la division par deux dans le calcul donne des résultats différents selon la version.

Pour la rendre cohérente, la force la sortie de la division à un entier:

p *= math.exp(int(mu - sigma * sigma/2)) * dt + 
    sigma * random.normalvariate(0, dt * dt)) 

Cela rend la sortie de la même dans les deux 2.x et 3.x. Un ensemble d'échantillons de sortie sur ma machine est:

0,0243898032782, 6126,78299771, ,00450839758621, 1,17316856812, ,00479489258202, 4.88995369021e-06, 0,033957530608, 29,9492464423, 3,16953460691

Cela semble être dans l'ordre de grandeur de ce que vous cherchez pour.

+0

Mais mon sigma est 1. Donc 'sigma * sigma/2' serait égal à' 0' dans Python 2.6. Ce n'est certainement pas ce que je veux. Je suis la formule GBM standard, et j'aurais besoin d'utiliser la division float pour le répliquer. – max

0

Utilisation division flottante (//) plutôt que la division entière (/) en Python 3.1 fonctionne:

import math 
import random 

p = 1 
dt = 1 
mu = 0 
sigma = 1 
for k in range(100): 
    p *= math.exp((mu - sigma * sigma // 2) * dt + 
     sigma * random.normalvariate(0, dt * dt)) 
print(p) 

Sur une course exemple, j'ai obtenu les numéros suivants:

0,0989269233704
2536660,91466
2146,09989782
0,502233504924
0,43052439984
14,1156450335

+1

// est une division entière, non flottante. J'ai vraiment besoin de float ... – max

Questions connexes