Создание списка индексов nxm массива a

Вот в чем проблема:

Для массива a numpy, содержащего n элементов, обозначим через b набор его уникальных значений в порядке возрастания, обозначим через m размер массива b. Вам нужно создать массив numpy с размерами n × m, в каждой строке которого должно быть значение 1 в случае, если оно равно значению данного индекса массива b, в других местах оно должно быть 0.

import numpy as np


def convert(a):
    b = np.unique(sorted(a))
    result = []
    for i in a:
        result.append((b == i) * 1)
    return np.array(result)


a = np.array([1, 1, 2, 3, 2, 4, 5, 2, 3, 4, 5, 1, 1])
b = np.unique(sorted(a))
print(convert(a))

Это мое решение. есть ли какие-то улучшения, которые я могу сделать? Я не уверен в том, что объявить обычный список для результата, а затем преобразовать его в np.array.

2 ответа
2

Удалять sorted

Из документов: numpy.unique возвращает отсортированные уникальные элементы массива.

Вы можете просто удалить вызов sorted:

b = np.unique(sorted(a))

# produces the same result as

b = np.unique(a)

Понимание списка

В большинстве случаев вы можете и должны избегать такой схемы создания списков:

result = []
for i in a:
    result.append((b == i) * 1)

Его можно заменить кратким пониманием списка и напрямую передать в np.array:

result = np.array([(b == i) * 1 for i in a])

# or directly return it (if applicable)
return np.array([(b == i) * 1 for i in a])

Понимание списков более питонично и часто быстрее. Как правило, не изменяя list объект также менее подвержен ошибкам.


Может быть лучший способ нанести на карту lambda x: (uniques == x) * 1 над входным массивом a. Вот обсуждение темы на StackOverflow: Самый эффективный способ сопоставить функцию с массивом numpy. Похоже на использование np.vectorize следует избегать по соображениям производительности.

С использованием map может быть похоже на понимание списка с точки зрения производительности (я сделал нет правильно протестируйте производительность здесь):

def convert_listcomp(a):
    uniques = np.unique(a)
    return np.array([(b == i) * 1 for i in a])

def convert_map(a):
    uniques = np.unique(a)
    return np.array(list(map(lambda x: (uniques == x) * 1, a)))

    Всегда есть однострочный вариант, предполагающий a это вектор-строка (1d массив):

    (a.reshape((-1, 1)) == np.unique(a)).astype(int)
    

    Это работает путем трансляции == операция. Посмотрим, как это сделать.

    Когда вы спрашиваете numpy чтобы применить операцию, сначала он проверяет, совместимы ли размеры. В противном случае возникает исключение. Например, попробуйте ввести np.ones(3) - np.ones(4) в переводчике. После нажатия Enter вы должны увидеть сообщение

    ValueError: operands could not be broadcast together with shapes (3,) (4,).
    

    Это происходит потому, что 3 != 4. Ага. Но это еще не все.

    Пытаться a.reshape((-1, 1)) == np.unique(a). Несмотря на n!=m обычно держится, numpy с радостью вычисляет матрицу формы (n, m). Почему?

    Это магия вещание:

    При работе с двумя массивами NumPy сравнивает их формы поэлементно. Он начинается с конечных (то есть крайних правых) размеров и продолжается влево. Два измерения совместимы, когда

    1. они равны, или

    2. один из них 1

    Если эти условия не выполняются, генерируется исключение ValueError: операнды не могут быть переданы вместе, указывая, что массивы имеют несовместимые формы. Размер результирующего массива — это размер, который не равен 1 по каждой оси входных данных.

    Как здесь применяется это правило? Ну форма x = a.reshape((-1, 1)) является (n, 1), форма y = np.unique(a) является (1, m), поэтому вторая точка сверху остается в силе. Поэтому numpy расширяется x от формы (n, 1) к xx формы (n, m) путем «копирования» (насколько мне известно, копирования не происходит) его значения по второй оси, т.е. соблюдая правило

    xx[j, k] = x[j] for all j=1..n, k=1..m.
    

    По аналогии, y расширяется от формы (1, m) к yy формы (n, m) уважая

    yy[j, k] = y[k] for all j=1..n, k=1..m
    

    и операция применяется к xx а также yy как обычно, т.е.

    x == y   ~>   xx == yy   ~>    :)
    

      Добавить комментарий

      Ваш адрес email не будет опубликован. Обязательные поля помечены *