Создать массив значений индекса из списка с другим списком Python - PullRequest
0 голосов
/ 03 марта 2019

У меня есть массив значений, а также другой массив, для которого я хотел бы создать индекс.Например:

value_list = np.array([[2,2,3],[255,243,198],[2,2,3],[50,35,3]])
key_list = np.array([[2,2,3],[255,243,198],[50,35,3]])
MagicFunction(value_list,key_list)
#result = [[0,1,0,2]] which has the same length as value_list

Решения, которые я увидел в Интернете после исследования, не совсем то, о чем я прошу, я верю, любая помощь будет оценена!У меня есть этот код перебора, который дает результат, но я даже не хочу проверять его на моем реальном размере данных

T = np.zeros((len(value_list)), dtype = np.uint32)
for i in range(len(value_list)):
    for j in range(len(key_list)):
        if sum(value_list[i] == key_list[j]) == 3:
            T[i] = j

Ответы [ 2 ]

0 голосов
/ 03 марта 2019

Допущения:

  1. Каждый элемент value_list будет присутствовать в key_list (в той или иной позиции)
  2. Нас интересует индекс в пределах key_list, только из first match

Решение:

Изиз двух массивов мы создаем представления из 3-х кортежей.Затем мы транслируем два вида в двух ортогональных направлениях, а затем проверяем поэлементное равенство на транслируемых массивах.

import numpy as np

value_list = np.array([[2,2,3],[255,243,198],[2,2,3],[50,35,3]], dtype='uint8')
key_list   = np.array([[2,2,3],[255,243,198],[50,35,3]], dtype='uint8')

# Define a new dtype, describing a "structure" of 3 uint8's (since
# your original dtype is uint8). To the fields of this structure,
# give some arbitrary names 'first', 'sec', and 'third'
dt = np.dtype([('first', np.uint8, 1),('sec', np.uint8, 1),('third', np.uint8, 1)])

# Now view the arrays as 1-d arrays of 3-tuples, using the dt
v_value_list = value_list.view(dtype=dt).reshape(value_list.shape[0])
v_key_list   = key_list.view(dtype=dt).reshape(key_list.shape[0])

result = np.argmax(v_key_list[:,None] == v_value_list[None,:], axis=0)
print (result)

Вывод:

[0, 1, 0, 2]

Примечания:

  1. Хотя это чистое решение без каких-либо видимых циклов, оно может иметь скрытую неэффективность, поскольку оно сопоставляет каждый элемент value_list с каждым элементомkey_list, в отличие от поиска на основе петель, который автоматически останавливается при первом успешном совпадении.Любое полученное преимущество будет зависеть от фактического размера key_list и от того, где произошли успешные совпадения, в key_list.По мере увеличения размера key_list преимущество в виде ноль может быть несколько ослаблено, особенно если успешные совпадения происходят в основном в более ранней части key_list.

  2. Представления, которыемы создаем фактически пустые структурированные массивы, где каждый элемент представления представляет собой структуру из двух int s.Один интересный вопрос, который я еще не исследовал, заключается в том, что, когда numpy сравнивает одну структуру с другой, выполняет ли она сравнение каждого поля в структуре или замыкает сравнение полей в первом ошибочном полеструктура?Любое такое короткое замыкание может означать небольшое дополнительное преимущество для этого решения со структурированным массивом.

0 голосов
/ 03 марта 2019

Вопрос в том, как сделать так, чтобы это было не очень неэффективно.Я вижу, что два подхода

  1. используют словарь, чтобы поиск был быстрым.numpy Массивы являются изменяемыми и поэтому не могут быть хешируемыми, поэтому вам придется преобразовывать их, например, в кортежи для использования со словарем.

  2. Используйте широковещательную рассылку для проверки value_listпротив каждого «ключа» в key_list векторизованным способом.Это по крайней мере выведет циклы for из Python, но вам все равно придется сравнивать каждое значение с каждым ключом.

Здесь я также предполагаю, что только key_listимеет уникальные «ключи».

Вот как вы могли бы сделать первый подход:

value_list = np.array([[2,2,3],[255,243,198],[2,2,3],[50,35,3]])
key_list = np.array([[2,2,3],[255,243,198],[50,35,3]])

key_map = {tuple(key): i for i, key in enumerate(key_list)}
result = np.array([key_map[tuple(value)] for value in value_list])
result # array([0, 1, 0, 2])

А вот второй:

result = np.where((key_list[None] == value_list[:, None]).all(axis=-1))[1]
result # array([0, 1, 0, 2])

Какой способ быстрее может зависетьна размер key_list и value_list.Я бы выбрал для вас оба типа массивов типичных размеров.

РЕДАКТИРОВАТЬ - как отмечалось в комментариях, второе решение выглядит не совсем корректным, но я не уверен, что делает его неудачным.Попробуйте вместо этого использовать первое решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...