Удаление дубликатов из списка массивов numPy
У меня есть обычный список Python, который содержит (многомерные) массивы numPy, все одинаковой формы и с одинаковым количеством значений. Некоторые массивы в списке являются дубликатами более ранних.
У меня есть проблема, что я хочу удалить все дубликаты, но тот факт, что тип данных-массивы numPy, немного усложняет это...
• я не могу использовать set() , так как массивы numPy не хешируются.
• Я не могу проверить наличие дубликатов во время вставки, так как массивы являются генерируется пакетами функцией и добавляется в список с помощью .расширять().
* массивы numPy напрямую не сопоставимы, не прибегая к одной из собственных функций numPy, поэтому я не могу просто взять что-то, что использует "if x in list"...
* Содержимое списка должно оставаться массивами numPy в конце процесса; я мог бы сравнить копии массивов, преобразованных во вложенные списки, но я не могу преобразовать массивы в прямые списки python постоянно.
Любые предложения о том, как я могу удалить дублирует эффективно здесь?
3 ответа:
Используя решения здесь: наиболее эффективное свойство хэширования для массива numpy мы видим, что хэширование лучше всего работает с A.tostring (), если a-массив numpy. Итак:
import numpy as np arraylist = [np.array([1,2,3,4]), np.array([1,2,3,4]), np.array([1,3,2,4])] L = {array.tostring(): array for array in arraylist} L.values() # [array([1, 3, 2, 4]), array([1, 2, 3, 4])]
В зависимости от структуры ваших данных, возможно, будет быстрее напрямую сравнить все массивы, а не искать какой-то способ хэширования массивов. Алгоритм O (n^2), но каждое отдельное сравнение будет намного быстрее, чем создание строк или списков python ваших массивов. Так что это зависит от того, сколько массивов вы должны проверить.
Напр.
uniques = [] for arr in possible_duplicates: if not any(numpy.array_equal(arr, unique_arr) for unique_arr in uniques): uniques.append(arr)
Вот один из способов использования
tuple
:>>> import numpy as np >>> t = [np.asarray([1, 2, 3, 4]), np.asarray([1, 2, 3, 4]), np.asarray([1, 1, 3, 4])] >>> map(np.asarray, set(map(tuple, t))) [array([1, 1, 3, 4]), array([1, 2, 3, 4])]
Если ваши массивы многомерны, то сначала расплющите их до размера 1 на любой массив, затем используйте ту же идею и измените их в конце:
def to_tuple(arr): return tuple(arr.reshape((arr.size,))) def from_tuple(tup, original_shape): np.asarray(tup).reshape(original_shape)
Пример:
In [64]: t = np.asarray([[[1,2,3],[4,5,6]], [[1,1,3],[4,5,6]], [[1,2,3],[4,5,6]]]) In [65]: map(lambda x: from_tuple(x, t[0].shape), set(map(to_tuple, t))) Out[65]: [array([[1, 2, 3], [4, 5, 6]]), array([[1, 1, 3], [4, 5, 6]])]
Другой вариант-создать
pandas.DataFrame
из вашихndarrays
(обрабатывая их как строки путем изменения формы, если это необходимо) и использовать встроенные модули pandas для унификации строк.In [34]: t Out[34]: [array([1, 2, 3, 4]), array([1, 2, 3, 4]), array([1, 1, 3, 4])] In [35]: pandas.DataFrame(t).drop_duplicates().values Out[35]: array([[1, 2, 3, 4], [1, 1, 3, 4]])
В целом, я думаю, что это плохая идея, чтобы попытаться использовать
tostring()
в качестве квази-хэша функция, потому что вам понадобится больше кода котельной плиты, чем в моем подходе, просто чтобы защитить от возможности того, что некоторые из содержимого мутируют после того, как им был назначен их "хэш" ключ в некоторомdict
.Если изменение формы и преобразование в
tuple
происходит слишком медленно, учитывая размер данных, я чувствую, что это выявляет более фундаментальную проблему: приложение не разработано хорошо вокруг потребностей (например, de-duping) и пытается втиснуть их в какой-то процесс Python, запущенный в память, вероятно, не тот путь. На этом этапе я бы остановился, чтобы рассмотреть, не является ли что-то вроде Cassandra, которая может легко строить индексы базы данных поверх больших столбцов (или многомерных массивов) данных с плавающей запятой (или других) более разумным подходом.