Как использовать NumPy функции, чтобы сделать этот список - PullRequest
0 голосов
/ 23 апреля 2019

Я пытаюсь ускорить понимание этого списка, я пытался использовать numpy.vectorize, но не смог заставить его работать.Можно ли использовать эту функцию и если да, то как или есть другой способ сделать это быстрее?Список «a» - это numpy ndarray (в 2D), поэтому я знаю, что для его ускорения вы должны использовать numpy функции, а не понимание списка, но не смогли найти, как это сделать, используя эти функции.

[[[255,255,255] if y else [0,0,0] for y in row ] for row in a]

Ответы [ 3 ]

2 голосов
/ 23 апреля 2019

Вы можете использовать np.where:

In [11]: np.where(a, np.array([255, 255, 255]), 0)
Out[11]:
array([[255, 255, 255],
       [  0,   0,   0],
       [255, 255, 255]]

Альтернативой является создание полного массива или нулевого массива, а затем обновление строк:

In [21] res = np.zeros((3, 3))

In [22]: np.where(a == 0, res, 255)
Out[22]:
array([[255., 255., 255.],
       [  0.,   0.,   0.],
       [255., 255., 255.]])
1 голос
/ 23 апреля 2019

Похоже, ваш список будет выглядеть примерно так:

In [22]: alist = [[0,1,2],[3,0,0]]                                              

И результат вашего понимания:

In [23]: [[[255,255,255] if y else [0,0,0] for y in row] for row in alist]      
Out[23]: 
[[[0, 0, 0], [255, 255, 255], [255, 255, 255]],
 [[255, 255, 255], [0, 0, 0], [0, 0, 0]]]

Чтобы сделать нечто подобное в numpy, создайте массив (все подсписки должны иметь одинаковую длину):

In [24]: arr = np.array(alist)                                                  
In [25]: arr                                                                    
Out[25]: 
array([[0, 1, 2],
       [3, 0, 0]])

Создать целевой массив - 3d фигура:

In [27]: res = np.zeros(arr.shape+(3,),int)                                     
In [28]: res                                                                    
Out[28]: 
array([[[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]],

       [[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]]])

Маска, где y не равно 0:

In [29]: mask = arr!=0                                                          
In [30]: mask                                                                   
Out[30]: 
array([[False,  True,  True],
       [ True, False, False]])

Эта маска выберет 3 элемента из res:

In [31]: res[mask]                                                              
Out[31]: 
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

Мы можем установить значения с помощью скаляра:

In [32]: res[mask] = 255                                                        
In [33]: res                                                                    
Out[33]: 
array([[[  0,   0,   0],
        [255, 255, 255],
        [255, 255, 255]],

       [[255, 255, 255],
        [  0,   0,   0],
        [  0,   0,   0]]])

или массива:

In [34]: res[mask] = [255,255,255]                                              
In [35]: res                                                                    
Out[35]: 
array([[[  0,   0,   0],
        [255, 255, 255],
        [255, 255, 255]],

       [[255, 255, 255],
        [  0,   0,   0],
        [  0,   0,   0]]])

Иногда при установке таких замаскированных массивов мы сталкиваемся с ошибками вещания - несоответствие между целевым массивом и источником.

Другой подход заключается в обработке mask как индексного массива 0/1:

In [37]: x = np.array([[0,0,0],[255,255,255]])                                  
In [39]: x[mask.astype(int)]                                                    
Out[39]: 
array([[[  0,   0,   0],
        [255, 255, 255],
        [255, 255, 255]],

       [[255, 255, 255],
        [  0,   0,   0],
        [  0,   0,   0]]])

Если вы начинаете со списков, подход к пониманию списка может быть самым быстрым.Несмотря на быструю индексацию массивов, преобразование списков в массивы связано со значительными издержками.

====

Чтобы сделать это с np.vectorize, я использую signature, что медленнее, чемобычный vectorize:

In [49]: np.vectorize(lambda y: np.array([255,255,255]) if y else np.array([0,0,
    ...: 0]), signature='()->(n)')(alist)                                       
Out[49]: 
array([[[  0,   0,   0],
        [255, 255, 255],
        [255, 255, 255]],

       [[255, 255, 255],
        [  0,   0,   0],
        [  0,   0,   0]]])
0 голосов
/ 26 апреля 2019

Попробовав еще кое-что, я нашел этот oneliner, который хорошо справляется со своей задачей.

    np.where(a != 0, 0, 255).repeat(3, 1).reshape(len(a), len(a[0]), 3)
...