(Удивительно сложно?) Numpy Векторизация - PullRequest
3 голосов
/ 17 апреля 2020

Я хочу найти способ избежать l oop в моем коде. Мне нужно реализовать следующую формулу, которая на первый взгляд проста:

formula

Другими словами: список индексов анализируется с именем I . Для каждого индекса, указанного в I , необходимо вычесть значения всех следующих индексов в массиве x . Сделайте некоторые вычисления на вычитаемом значении. Подведите итоги. Готово.

Мой текущий код:

def loss(x, indices):
    """ 
    Args:
        x: array_like, dtype=float
        indices: array_like, dtype=int

    Example:
        >>> x = np.array([0.3, 0.5, 0.2, 0.1, 1.2, 2.4, 2.8, 1.5, 3.2])
        >>> indices = np.array([0, 2, 3, 6])
        >>> print(loss(x, indices))
        21.81621815885847
    """

    total = 0.0
    for index in indices:
        # Broadcasting here, as all values from all following indices have
        # to be subtracted from the value at the given i index.
        difference = x[index] - x[index + 1:]

        # Sum all up
        log_addition = 1.0 + np.log(np.abs(difference))
        total += np.sum(log_addition)

    return total

Сложным является то, что индексы 'i' случайным образом распределены по всему диапазону выходных данных. Есть идеи?

1 Ответ

4 голосов
/ 17 апреля 2020

Вот один с NumPy -векторизацией -

mask = indices[:,None] < np.arange(len(x))
v = x[indices,None] - x
vmasked = v[mask]
log_addition = np.log(np.abs(vmasked))
out = log_addition.sum() + mask.sum()

В качестве альтернативы, используя l aws журнала, мы можем заменить последние два шага на -

out = np.log(np.prod(np.abs(vmasked))).sum() + mask.sum()

Вытолкнув abs, чтобы он работал вместо скаляра, он будет -

out = np.log(np.abs(np.prod(vmasked))).sum() + mask.sum()

Опять же, мы можем использовать multi-cores с numexpr -

import numexpr as ne
out = np.log(np.abs(ne.evaluate('prod(vmasked)'))) + mask.sum()

Если вы обнаружите, что даже v имеет слишком много нежелательных элементов, мы можем напрямую go до vmasked с -

xi = x[indices]
x2D = np.broadcast_to(x, (len(indices),len(x)))
vmasked = np.repeat(xi,mask.sum(1))-x2D[mask]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...