numpy - минимальный подмассив - PullRequest
       19

numpy - минимальный подмассив

0 голосов
/ 26 февраля 2020

У меня есть 3-мерный numpy ndarray.

Например, массив 4x4x2 выглядит следующим образом:

array = [
 [ [7 1] [8 0] [2 0] [7 1] ]
 [ [5 4] [1 4] [6 7] [8 1] ]
 [ [3 2] [4 5] [8 6] [6 2] ]
 [ [6 4] [1 2] [5 5] [7 1] ]
]

Мне нужно найти минимальный вложенный внутренний массив (тот, что с двумя числами) и его индексы, сравниваемые как обычно Python: сравните первую пару элементов, если равно, сравните следующую пару, ...

Ожидаемый результат для примера массива: value=[1 2], indices=(3, 1)

Чистый Python код для поиска самого элемента будет выглядеть следующим образом:

min(nested2 for nested1 in array for nested2 in nested1)

Однако я бы предпочел решение numpy, поскольку массивы довольно огромный ...

Ответы [ 2 ]

2 голосов
/ 26 февраля 2020

Ваше желаемое поведение зависит от Python, делающего лексическую сортировку списка списков. То есть подсписки сравниваются как:

In [275]: [1,2]<[2,0]                                                                          
Out[275]: True

np.sort выполняет только лексическую сортировку со структурированными массивами и комплексными значениями.

In [288]: alist = [ 
     ...:  [ [7, 1], [8, 0], [2, 0], [7, 1] ], 
     ...:  [ [5, 4], [1, 4], [6, 7], [8, 1] ], 
     ...:  [ [3, 2], [4, 5], [8, 6], [6, 2] ], 
     ...:  [ [6, 4], [1, 2], [5, 5], [7, 1] ] 
     ...: ]                                                                                    
In [289]: arr = np.array(alist)                                                                
In [290]: arr                                                                                  
Out[290]: 
array([[[7, 1],
        [8, 0],
        [2, 0],
        [7, 1]],

       [[5, 4],
        [1, 4],
        [6, 7],
        [8, 1]],

       [[3, 2],
        [4, 5],
        [8, 6],
        [6, 2]],

       [[6, 4],
        [1, 2],
        [5, 5],
        [7, 1]]])

Давайте попробуем сложный маршрут:

In [291]: x = np.dot(arr, [1,1j])                                                              
In [292]: x                                                                                    
Out[292]: 
array([[7.+1.j, 8.+0.j, 2.+0.j, 7.+1.j],
       [5.+4.j, 1.+4.j, 6.+7.j, 8.+1.j],
       [3.+2.j, 4.+5.j, 8.+6.j, 6.+2.j],
       [6.+4.j, 1.+2.j, 5.+5.j, 7.+1.j]])
In [293]: np.min(x)                                                                            
Out[293]: (1+2j)
In [294]: np.argmin(x)                                                                         
Out[294]: 13
In [295]: np.unravel_index(13, x.shape)                                                        
Out[295]: (3, 1)

Некоторые временные тесты:

In [302]: timeit min(nested2 for nested1 in alist for nested2 in nested1)                      
2.24 µs ± 19.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [303]: timeit min(arr.reshape(-1,2).tolist())                                               
2.53 µs ± 13.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [304]: timeit np.min(arr.dot([1,1j]))                                                       
19.5 µs ± 46.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Сложный маршрут может быть быстрее, когда массив намного больше, но в этом примере он хуже.

===

Подход структурированного массива:

In [320]: import numpy.lib.recfunctions as rf                                                  
In [321]: rf.unstructured_to_structured(arr, names=['x','y'])                                  
Out[321]: 
array([[(7, 1), (8, 0), (2, 0), (7, 1)],
       [(5, 4), (1, 4), (6, 7), (8, 1)],
       [(3, 2), (4, 5), (8, 6), (6, 2)],
       [(6, 4), (1, 2), (5, 5), (7, 1)]],
      dtype=[('x', '<i8'), ('y', '<i8')])
In [322]: np.argsort(rf.unstructured_to_structured(arr, names=['x','y']).ravel())              
Out[322]: array([13,  5,  2,  8,  9,  4, 14, 11, 12,  6,  0,  3, 15,  1,  7, 10])
In [323]: timeit np.argsort(rf.unstructured_to_structured(arr, names=['x','y']).ravel())       
41.3 µs ± 192 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
0 голосов
/ 26 февраля 2020
arr1 = np.array(array) # convert your list to numpy array
arr2 = np.sum(arr1,axis=2) # get the sum of the two elements in each array
ind1 = np.unravel_index(arr2.argmin(), arr2.shape) # the indices of the minimum sum
min1 = arr1[ind1] # the value of the minimum array
print(ind1)
(3, 1)
print(min1)
array([1, 2])
...