Как я могу создать новый список каждые x шагов в цикле? - PullRequest
0 голосов
/ 26 октября 2018

Я строю некоторые функции случайного блуждания на python и пытаюсь создать его, чтобы он брал местоположения случайных блужданий каждые 1000 шагов, а затем отображал их в гистограмме. Я понимаю, что могу буквально создавать новый список для n = 1000, 2000 и т. Д. Каждый раз и просто добавлять значения этого шага в этот список, но есть ли способ заставить Python создавать новый список каждые 1000 шагов?

import numpy as np 
import matplotlib.pyplot as plt

def random_walk(N,d):       
    walk = d*np.cumsum(2*np.random.binomial(1,.6,N)-1)
    return walk
n1=[]
n2=[]
n3=[]
n4=[]
n5=[]

for k in range(5000):
    particular_walk = random_walk(5000,2)
    n1.append(particular_walk[1000])
    n2.append(particular_walk[2000])
    n3.append(particular_walk[3000])
    n4.append(particular_walk[4000])
    n5.append(particular_walk[-1])


plt.hist(n1,bins=20,histtype='step',density=True)
plt.hist(n2,bins=20,histtype='step',density=True)
plt.hist(n3,bins=20,histtype='step',density=True)
plt.hist(n4,bins=20,histtype='step',density=True)
plt.hist(n5,bins=20,histtype='step',density=True)
plt.show()

Это код, который у меня есть, но я понимаю, что он не работает. Я знаю, что мог бы просто иметь список, называемый, скажем, «средняя точка», и установить его для местоположений конкретного маршрута на 2500, но есть ли способ сделать это автоматически?

Ответы [ 2 ]

0 голосов
/ 26 октября 2018

Как правило, вы хотите исключить использование списков при работе с numpy. Массивы намного более эффективны с точки зрения времени и пространства. Вам также следует избегать использования явных циклов Python, поскольку векторизация, предоставляемая numpy, будет намного быстрее.

Допустим, вы хотели сделать это для Z различных прогулок, где Z = 5000 в вашем примере, но вы хотите, чтобы оно было больше в общем случае. Вы можете использовать тот факт, что большинство отдельных функций могут быть применены к определенной оси, чтобы выполнить это:

import numpy as np 
from matplotlib import pyplot as plt

Z = 5000
N = 5000
d = 2

all_walks = d * np.cumsum(2 * np.random.binomial(1, 0.6, size=(Z, N)) - 1, axis=1)

Установка размера шагов на (Z, N) даст вам матрицу, содержащую Z строк, каждая строка с N шагами. Взятие совокупной суммы с axis=1 означает суммирование по столбцам. Теперь каждый ряд - это самостоятельная прогулка. Вы можете использовать очень простые нарезки, чтобы получить любой столбец, который вы хотите. n-й столбец будет содержать n -й шаг от каждой из Z прогулок. Причина, по которой вы хотите создать столбцы срезов, заключается в том, что построение графиков становится намного проще.

Давайте посмотрим на n=1000:

n1k = all_walks[:, 1000]
plt.hist(n1k, bins=20, histtype='step', density=True)

Пока все хорошо. Чтобы взять каждые 1000 выборок, используйте размер шага в индексе:

n = 1000
samples = all_walks[:, n::n]

samples теперь массив Zx (N // n) -1 ((5000, 4)), содержащий шаги с индексами 1000, 3000, 4000 в каждом массиве. Похоже, вы хотите иметь пять образцов в этом примере. На мой взгляд, есть три разумных способа сделать это:

  1. Начать с индекса 0: samples = all_walks[:, ::n]
  2. Начать с индекса n-1: samples = all_walks[:, n-1::n]
  3. Добавьте дополнительный шаг (столбец) к вашим прогулкам:

    all_walks = ... size=(Z, N+1) ...
    samples = all_walks[:, n::n]
    

Я не думаю, что возиться с пробелами из-за непоследовательного добавления индекса -1 - это особенно хорошая идея. Вместо этого я буду использовать вариант № 2 (помните, что индекс 999 содержит 1000-й шаг).

Хорошей новостью является то, что matplotlib позволяет вам строить столбцы вектора одновременно:

plt.hist(samples, bins=20, histtype='step', density=True)

Таким образом, весь сценарий на самом деле довольно короткий:

import numpy as np 
from matplotlib import pyplot as plt

Z = 5000
N = 5000
d = 2
n = 1000

all_walks = d * np.cumsum(2 * np.random.binomial(1, 0.6, size=(Z, N)) - 1, axis=1)
samples = all_walks[:, n-1::n]
plt.hist(samples, bins=20, histtype='step', density=True)
plt.show()

Если по какой-то причине вы не можете держать массив размером Z * N, плавающий в памяти все сразу, вы можете реализовать строку all_walks, используя цикл, который генерирует одну прогулку за раз, что-то вроде того, что вы изначально пытались делать. Помните, это только в том случае, если вы набрали Z какое-то невероятно большое число или по какой-то причине у вас нет ОЗУ:

samples = np.empty((Z, N//n))
for row in range(Z):
    walk = d * np.cumsum(2 * np.random.binomial(1, 0.6, size=N) - 1)
    samples[row] = walk[n-1::n]

Если вы начинаете с одного и того же случайного начального числа, оба метода должны давать одинаковые результаты. Основное отличие состоит в том, что первое занимает больше памяти, а второе занимает больше времени.

0 голосов
/ 26 октября 2018

Возможно, вы могли бы использовать словари python и создавать списки внутри словарей.

Это может быть что-то вроде этого:

if k%1000 == 0:
    rw_dict[str(k/1000)]=[]

Где str (k / 1000) - это просто имя ключа в словаре: 1.0, 2.0 и т. Д. Каждый раз, когда вам нужно выполнить операции с этим конкретным списком, вы можете получить доступ к списку с помощью rw_dict [list_name].

Надеюсь, это поможет!

...