#python
#python
Вопрос:
У меня есть набор данных из двумерного нормального, однако каждая точка данных берется из другого члена семейства, т. Е. Среднее значение и ковариационная матрица различаются. Я пытаюсь оптимизировать свой код, и мне интересно, есть ли лучший способ сделать это, пожалуйста.
На данный момент я использую понимание списка и пробовал параллелизм без особого успеха. Для 100 000 точек данных понимание списка завершается примерно за 8 секунд, а параллелизм занимает примерно на пару секунд больше.
Размер моих данных может составлять от нескольких сотен тысяч до пары миллионов, но данные всегда будут из двумерного гауссова. Также, как я уже сказал, каждая точка данных берется из двумерного гауссова с разным средним и ковариацией, но в приведенном ниже фрагменте кода я беру простейший возможный случай и передаю одну и ту же ковариацию и среднее значение для всех данных.
Любые идеи приветствуются!
import numpy as np
import pandas as pd
from multiprocessing.dummy import Pool as ThreadPool
from multiprocessing import cpu_count
from scipy.stats import multivariate_normal
from timeit import timeit
def mvn_loglik(param):
out = [multivariate_normal.logpdf(p[0], p[1], p[2]) for i, p in enumerate(param)]
return out
def mvn_loglik_helper(p):
out = multivariate_normal.logpdf(p[0], p[1], p[2])
return out
def mvn_loglik_par(param):
n = max(1, cpu_count() - 1)
pool = ThreadPool(n)
results = pool.map(mvn_loglik_helper, param)
pool.close()
pool.join()
return results
n = 100000
data = np.zeros([n,2])
mu = np.zeros([n,2])
cov = np.tile(np.eye(2,2), (n,1,1))
param = list(zip(*[data, mu, cov]))
assert np.all(mvn_loglik(param) == mvn_loglik_par(param))
def f():
param = list(zip(*[data, mu, cov]))
return mvn_loglik(param)
def g():
param = list(zip(*[data, mu, cov]))
return mvn_loglik_par(param)
print(timeit(f, number=1))
8.6705456
print(timeit(g, number=1))
10.187561600000002
Комментарии:
1. Я думаю, что этот код был оптимизирован, и, на мой взгляд, больше так быть не может. Вы не можете оптимизировать его с помощью программного обеспечения, но вы можете сделать это, обновив аппаратное обеспечение (ваш компьютер). Или вы можете использовать сервис Google (GoogleColab).
2. Зачем вам нужно создавать список? Не могли бы вы использовать результат вашего алгоритма поэлементно, используя
yield
конструкцию. Построение списка и доступ к нему довольно дороги, иyield
оператор — это удивительный и пугающий способ избежать этого, генерируя подразумеваемую вычисляемую последовательность «на лету» по мере необходимости.