Проверить, существует ли сгенерированная матрица

для проекта машинного обучения я генерирую случайные матрицы. Новая матрица, которой еще не существует, хранится в массиве. Если создается матрица, которая уже существует, ее не следует добавлять. Пока я делаю это с помощью цикла и функции allclose numpy для сравнения каждой матрицы в массиве с фактически созданной случайной матрицей. Однако мне нужно 500000 матриц, и код займет соответственно много времени. Знаете ли вы лучшее решение для сравнения матрицы с каждой матрицей в массиве? Буду признателен за любую помощь. Вот мой фактический код:

import numpy as np
 
a_total = np.zeros((1,3,3))
while j < 500000:
    atol = 1e-06
    h = 0
    a_add = np.random.rand(3,3).reshape(1,3,3)
    for y in range(a_total.shape[0]):
        mask = np.allclose(a_total[y], a_add, atol)
        if mask == False:
            h+=1
    if (h==a_total.shape(0)):
        a_total = np.concatenate((a_total, a_add), axis=0)
        j=+1

person mawa23    schedule 02.07.2020    source источник
comment
Одно из предложений — использовать менее строгую проверку перед полной поэлементной проверкой, например, просто проверить равенство первого элемента матриц (с точностью до допуска), и только если это отличается, выполнить полную поэлементную проверку чтобы убедиться, что все элементы различны перед добавлением   -  person Jimmy    schedule 02.07.2020
comment
Однако, если это для какого-то моделирования Монте-Карло, мне интересно, почему вы избавляетесь от сценариев, которые идентичны более ранним, поскольку это изменит статистическое свойство процесса, который вы пытаетесь смоделировать - я знаю, что это не ваш вопрос так что просто мысль...   -  person Jimmy    schedule 02.07.2020
comment
Добавьте в свой код переменную «a = 8.0000001». После создания матрицы вычислите сумму матрицы. Затем измените любой из элементов матрицы равным «а-сумма». Затем увеличьте a как «a+=0.00000001» и продолжайте. Таким образом, вся ваша матрица будет уникальной. В зависимости от количества матриц вы можете добавить больше или меньше нулей в 8.00000001.....   -  person Rahul Vishwakarma    schedule 02.07.2020
comment
Убедитесь, что вы используете значения float64   -  person Rahul Vishwakarma    schedule 02.07.2020


Ответы (1)


Я предполагаю, что случайные массивы предназначены только для примера, потому что вероятность получения одного дубликата в n = 500000 записей 9-элементных массивов равна 1e-6**9*n**2 = 1e-43, что исчезающе мало.

Если вам казалось, что ваш код работает вечно, это из-за этой строки:

    j=+1

Который, вероятно, должен был быть j += 1. Кроме того, это:

    a_total = np.concatenate((a_total, a_add), axis=0)

это медленная операция - она ​​скопирует весь массив. Вместо этого вы должны предварительно выделить.

Самый эффективный способ — создать хэш или хешируемый объект из ваших массивов и сохранить их.

import numpy as np
n = 500000
 
a_total = np.zeros((n, 3, 3))
seen = set()
j = 0
atol=1e-6
q = int(0.5/atol)

while j < n:
    a_add = np.random.rand(3,3)
        
    a_int = (a_add * q).astype(np.int32).ravel()
    a_bytes = a_int.tobytes()
    if a_bytes in seen:
        continue
    seen.add(a_bytes)
    a_total[j, :, :] = a_add
    j += 1

Это будет запущено через несколько секунд. Это не совсем соответствует вашему требованию, потому что с atol=1e-6, 1.9e-6 и 2.1e-6 (разница 0.2e-6) будут считаться разными, тогда как 2.1e-6 и 3.9e-6 (разница 1.8e-6) будут считаться одинаковыми. Но, возможно, это приемлемо для вашего приложения.

Если проблема с памятью для seen, вы можете рассмотреть возможность использования hash(a_bytes), который представляет собой 8-байтовый хэш (по сравнению с 36 байтами для хранения всего массива). Я сомневаюсь, что это стоит проблем с массивами 3x3, но вы можете подумать об этом, если ваш фактический вариант использования имеет большие массивы.

person Han-Kwang Nienhuys    schedule 02.07.2020