2016-08-01 2 views
2

Я хочу генерировать восемь случайных чисел в диапазоне (от 0 до pi/8), добавлять их вместе, принимать синус этой суммы и после этого N раз, возьмите средний результат. После масштабирования я получаю правильный ответ, но он слишком медленный для N > 10^6, особенно когда я усредняю ​​по N пробкам n_t = 25 еще раз! Я в настоящее время получаю этот код для запуска около 12 секунд для N = 10^5, что означает, что это займет 20 минут для N = 10^7, что кажется не оптимальным (может быть, я не знаю!).Оптимизация генерации большого числа случайных чисел с использованием python 3

Мой код выглядит следующим образом:

import random 
import datetime 
from numpy import pi 
from numpy import sin 
import numpy 
t1 = datetime.datetime.now() 

def trial(N): 
    total = [] 
    uniform = numpy.random.uniform 
    append = total.append 
    for j in range(N): 
     sum = 0 
     for i in range (8): 
      sum+= uniform(0, pi/8) 
     append(sin(sum)) 
    return total 

N = 1000000 
n_t = 25 
total_squared = 0 
ans = [] 
for k in range (n_t): 
    total = trial(N) 
    f_mean = (numpy.sum(total))/N 
    ans.append(f_mean*((pi/8)**8)*1000000) 
sum_square = 0 
for e in ans: 
    sum_square += e**2 
sum = numpy.sum(ans) 
mean = sum/n_t 
variance = sum_square/n_t - mean**2 
s_d = variance**0.5 
print (mean, " ± ", s_d) 
t2 = datetime.datetime.now() 
print ("Execution time: %s" % (t2-t1)) 

Если кто-нибудь может мне помочь оптимизировать этот он будет высоко ценится!

Спасибо :)

+0

Какова цель? Если это просто вычисление в среднем, сделайте математику, а не длительную симуляцию, которая в любом случае пострадает от статистической ошибки. – Julien

+0

Итак, вы хотите генерировать 2 * миллиард * случайных чисел? Это, безусловно, потребует времени. – justhalf

+0

Возможно немного ускорение с 'sum = numpy.sum (numpy.random.random_sample (8)) * pi_8' –

ответ

5

С учетом вашего требования получить результат с помощью этого метода, np.sin(np.random.uniform(0,np.pi/8,size=(8,10**6,25)).sum(axis=0)).mean(axis=0) доставит вам ваши 25 проб довольно быстро ... Это полностью векторизованное (и краткое, что всегда является бонусом!), Поэтому я сомневаюсь, что вы могли бы сделать лучше. .

Объяснение:

Вы генерировать большой случайный 3d массив размером (8 x 10**6 x 25). .sum(axis=0) доставит вам сумму по первому измерению (8). np.sin(...) применяется по-разному. .mean(axis=0) вы получите среднее значение по сравнению с первым оставшимся размером (10**6) и оставьте 1d массив длины (25), соответствующий вашим испытаниям.

+0

Спасибо! Как это работает и как это реализовать? Извините, я только начал изучать python неделю назад, поэтому я не очень понимаю, что я делаю! –

+0

Что ты имеешь в виду? копия и вставка должны работать ... – Julien

+0

Сначала это сгенерирует все в памяти, верно? Поэтому для N = 1e7 потребуется не менее 8 ГБ. Все еще хорошо в некоторых современных компьютерах, но это не так дешево с точки зрения памяти. Однако хороший подход к векторам. +1 – justhalf

1

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

Сумма восьми равномерных переменных имеет колоколообразное распределение по диапазону [0, π]. Если я прав, распределение может быть представлено как B-сплайн порядка 8. Взятие синуса дает значение в диапазоне [0, 1]. Вы можете найти математическое ожидание μ и дисперсию σ² путем простого численного интегрирования.

Затем используйте обычный генератор со средним μ и дисперсией σ²/N. Это будет мгновенно в сравнении.

+2

хорошо, если вы собираетесь заниматься математикой, не останавливайтесь на полпути;) – Julien

+0

@JulienBernu: Я не останавливаюсь на полпути. Я рассказываю OP, как он может генерировать случайную переменную, которая имеет те же характеристики, что и одна, вычисленная из значений 8N. Но это все еще случайное значение. –