Как я могу оптимизировать этот код Python, пожалуйста?

#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 оператор — это удивительный и пугающий способ избежать этого, генерируя подразумеваемую вычисляемую последовательность «на лету» по мере необходимости.