2016-05-05 8 views
0

У меня есть код Matlab, который генерирует 1D случайное блуждание.1D Случайная прогулка от Matlab до Python

%% probability to move up or down 
prob = [0.05, 0.95]; 

start = 2; %% start with 2 
positions(1) = start; 

for i=2:1000 
    rr = rand(1); 
    down = rr<prob(1) & positions(i-1)>1; 
    up = rr>prob(2) & positions(i-1)<4; 
    positions(i) = positions(i-1)-down + up; 
figure(1), clf 
plot(positions) 

Это дает мне сюжет ниже 1D Random Walk with Matlab

мне нужно, чтобы попытаться перевести это в Python, и я пришел с этим (с помощью NumPy):

import random 
import numpy as np 
import matplotlib.pyplot as plt 

prob = [0.05, 0.95] ##probability to move up or down 
N = 100 ##length of walk 

def randomWalk(N): 
    positions=np.zeros(N) 
    start = 2 ##Start at 2 
    positions[0] = start 
    for i in range(1,100): 
     rr = random.randint(0,1) 

     if rr<prob[0] and positions[i-1]>1: 
      start -= 1 
     elif rr>prob[1] and positions[i-1]<4: 
      start += 1 
     positions[i] = start 
    return positions 

plt.plot(randomWalk(N)) 
plt.show() 

Это выглядит довольно близко (см. рисунок ниже): 1D Random Walk with Python

Но мне интересно, действительно ли они эквивалентны, потому что они кажутся разными: код Python кажется s пикье, чем у Матлаба.

Что не хватает в моем коде Python для достижения идеального пошагового увеличения/уменьшения (аналогично коду Matlab)? Возможно, ему нужно «другое», которое говорит ему оставаться неизменным, если не выполняются два условия. Как это реализовать?

ответ

0

Вы делаете кучу вещей по-разному.

Во-первых, вы используете rand в MATLAB, который возвращает случайное значение с 0 до 1. В python вы используете randint, который возвращает случайное целое число. Вы делаете randint(0, 1), что означает «случайное целое число от 0 до 1, не считая 0». Так что это всегда будет 1. Вы хотите random.random(), которая возвращает случайный поплавок между 0 и 1.

Далее вы вычислительный downиup в MATLAB, но в Python вы вычислительное downилиup в Python. Для вашего конкретного случая вероятностей они в конечном итоге имеют одинаковый результат, но они синтаксически различны. В этом случае вы можете использовать почти идентичный синтаксис для MATLAB для Python.

Наконец, вы вычисляете намного больше образцов для MATLAB, чем Python (примерно в 10 раз).

Вот прямой порт вашего кода MATLAB на Python. Результат для меня почти так же, как ваш пример MATLAB (с различными случайными числами, конечно):

import random 
import matplotlib.pyplot as plt 

prob = [0.05, 0.95] # Probability to move up or down 

start = 2 #Start at 2 
positions = [start] 

for _ in range(1, 1000): 
    rr = random.random() 
    down = rr < prob[0] and positions[-1] > 1 
    up = rr > prob[1] and positions[-1] < 4 
    positions.append(positions[-1] - down + up) 

plt.plot(positions) 
plt.show() 

Если скорость является проблемой, вероятно, можно ускорить этот процесс с помощью np.random.random(1000) для генерации случайных чисел до -front, а также проводить сопоставления вероятностей вверх, а также векторизованным образом.

Так что-то вроде этого:

import random 
import numpy as np 
import matplotlib.pyplot as plt 

prob = [0.05, 0.95] # Probability to move up or down 

start = 2 #Start at 2 
positions = [start] 

rr = np.random.random(1000) 
downp = rr < prob[0] 
upp = rr > prob[1] 

for idownp, iupp in zip(downp, upp): 
    down = idownp and positions[-1] > 1 
    up = iupp and positions[-1] < 4 
    positions.append(positions[-1] - down + up) 

plt.plot(positions) 
plt.show() 

Edit: Для того, чтобы объяснить немного больше о втором примере, в основном то, что я делаю, заранее вычисляя ли вероятность ниже первого порогового значения или выше второго для каждый шаг впереди времени. Это намного быстрее, чем вычисление случайной выборки и сравнение на каждом этапе цикла. Затем я использую zip, чтобы объединить эти две случайные последовательности в одну последовательность, где каждый элемент представляет собой пару соответствующих элементов из двух последовательностей. Это предполагает python 3, если вы используете python 2, вы должны использовать itertools.izip вместо zip.

Так что примерно эквивалентно следующему:

import random 
import numpy as np 
import matplotlib.pyplot as plt 

prob = [0.05, 0.95] # Probability to move up or down 

start = 2 #Start at 2 
positions = [start] 

rr = np.random.random(1000) 
downp = rr < prob[0] 
upp = rr > prob[1] 

for i in range(len(rr)): 
    idownp = downp[i] 
    iupp = upp[i] 
    down = idownp and positions[-1] > 1 
    up = iupp and positions[-1] < 4 
    positions.append(positions[-1] - down + up) 

plt.plot(positions) 
plt.show() 

В Python, как правило, предпочтительно, чтобы итерации по значениям, а не индексов. Практически никогда не бывает ситуации, когда вам нужно перебирать индекс. Если вы обнаружите, что делаете что-то вроде for i in range(len(foo)):, или что-то подобное этому, вы почти наверняка делаете что-то неправильно. Вам необходимо либо перебрать foo, либо если вам нужен индекс для чего-то другого, вы можете использовать что-то вроде for i, ifoo in enumerate(foo):, которое доставит вам как элементы foo, так и их индексы.

Итерация по индексам распространена в MATLAB из-за различных ограничений на языке MATLAB. Технически возможно сделать что-то похожее на то, что я сделал на этом примере Python в MATLAB, но в MATLAB для этого требуется много шаблонов, которые будут безопасными и в большинстве случаев будут очень медленными. В Python, однако, это самый быстрый и чистый подход.

+0

Большое вам спасибо @TheBlackCat! Если вы не возражаете, не могли бы вы объяснить, что именно делает эта строка во втором фрагменте кода: «для idownp, iupp в zip (downp, upp)». Я понимаю часть zip, но мне интересно о «idown» и «iup»? – Spica

+0

Ответ на этот вопрос - слишком много для комментария, поэтому я отредактировал свой первоначальный ответ, чтобы включить объяснение. См. Изменения. Если это еще не ясно, пожалуйста, напишите еще один комментарий, объясняющий далее, что неясно. – TheBlackCat

+0

Большое спасибо за подробный ответ, TheBlackCat! Я вообще не знал о проблеме итерации по индексу, я узнал что-то новое и полезное, я могу использовать в других скриптах! – Spica

Смежные вопросы