2014-11-13 8 views
3

У меня есть два 2D numpy массивов,Карты Numpy в `in1d` над 2D массивом

import numpy as np  
a = np.array([[ 1, 15, 16, 200, 10], 
       [ -1, 10, 17, 11, -1], 
       [ -1, -1, 20, -1, -1]]) 

g = np.array([[ 1, 12, 15, 100, 11], 
       [ 2, 13, 16, 200, 12], 
       [ 3, 14, 17, 300, 13], 
       [ 4, 17, 18, 400, 14], 
       [ 5, 20, 19, 500, 16]]) 

То, что я хочу сделать, это, для каждого столбца g, чтобы проверить, если он содержит какой-либо элемент из соответствующего столбца a. Для первого столбца я хочу проверить, появляется ли какое-либо из значений [1,2,3,4,5] в [1,-1,-1] и возвращает True. Во-вторых, я хочу вернуть False, потому что в [12,13,14,17,20] элемент не появляется в [15,10,-1]. На данный момент я делаю это с помощью понимания списка Python. Запуск

result = [np.any(np.in1d(g[:,i], a[:, i])) for i in range(5)] 

вычисляет правильный результат, но становится медленным, когда a имеет много столбцов. Есть ли более «чистый» numpy «способ сделать то же самое? Я чувствую, что должно быть ключевое слово axis, которое можно добавить к функции numpy.in1d, но нет ...

+0

К сожалению, мой ответ был неправильным. – Gioelelm

+0

- это количество строк 'a' и' g' small, как в примере? – gg349

+0

@GiulioGhirardo Извините за то, что вы так долго отвечали: количество строк 'a' и' g' намного меньше числа столбцов. 'g' имеет не более 10 строк, а' a' - не более 100. Число столбцов от 10 000 до 20 000 – 5xum

ответ

1

Я хотел бы использовать вещание трюков, но это очень сильно зависит от размера ваших массивов и объема оперативной памяти, доступного для вас:

M = g.reshape(g.shape+(1,)) - a.T.reshape((1,a.shape[1],a.shape[0])) 
np.any(np.any(M == 0, axis=0), axis=1) 
# returns: 
# array([ True, False, True, True, False], dtype=bool) 

Это проще объяснить с куском бумаги и ручкой (и меньшие тестовые массивы) (см. ниже), но в основном вы делаете копии каждого столбца в g (по одной копии для каждой строки в a) и вычитаете из этих копий отдельные элементы, взятые из соответствующего столбца в a. Подобно оригинальному алгоритму, просто векторизованному.

Caveat: если какой-либо из массивов g или a является 1D, вам нужно, чтобы заставить его стать 2D, так что его форма, по крайней мере (1,n).

набирает скорость:

  • , основанная только на массивах: фактор ~ 20

    • питон для петель: 301us в петлю
    • векторизации: 15.4us за петлю
  • большие массивы: коэффициент ~ 80

    In [2]: a = np.random.random_integers(-2, 3, size=(4, 50)) 
    
    In [3]: b = np.random.random_integers(-20, 30, size=(35, 50)) 
    
    In [4]: %timeit np.any(np.any(b.reshape(b.shape+(1,)) - a.T.reshape((1,a.shape[1],a.shape[0])) == 0, axis=0), axis=1) 
    10000 loops, best of 3: 39.5 us per loop 
    
    In [5]: %timeit [np.any(np.in1d(b[:,i], a[:, i])) for i in range(a.shape[1])] 
    100 loops, best of 3: 3.13 ms per loop 
    

изображение прилагается объяснить вещания: broadcasting explained

+0

следить за улучшением производительности. Это действительно зависит от данных. Если вы возьмете за свои 'a, b' размеры' (4000, 15) 'и' (3500, 15) ', которые вполне разумны, ваши решения намного медленнее, чем мои, а также от того, , – gg349

+0

Вы абсолютно правы, и достаточно веская причина для этого - оценка короткого замыкания, которую вы используете, которая вступает в игру сначала с размерами, которые вы выбрали (количество строк намного больше, чем количество столбцов). Но это также зависит от значений, присутствующих в 'a' и' g', как вы говорите (в приведенном выше примере диапазон значений довольно ограничен). –

+0

Мне нравится этот ответ, но не совсем понимаю. Вычитаемые массивы, т. Е. 'G.reshape (g.shape + (1,))' и 'a.T.reshape ((1, a.shape [1], a.shape [0]))', они имеют разные формы. Первый - (1,5,3), а второй - (5,5,1). Как вычитание даже работает в этом случае? – 5xum

1

Вместо обработки ввода по столбцу вы можете обрабатывать его по строкам. Например, вы узнаете, присутствует ли какой-либо элемент первой строки a в столбцах g, чтобы вы могли прекратить обработку столбцов, в которых найден элемент.

idx = arange(a.shape[1]) 
result = empty((idx.size,), dtype=bool) 
result.fill(False) 

for j in range(a.shape[0]): 
    #delete this print in production 
    print "%d line, I look only at columns " % (j + 1), idx 
    line_pruned = take(a[j], idx) 
    g_pruned = take(g, idx, axis=1) 
    positive_idx = where((g_pruned - line_pruned) == 0)[1] 
    #delete this print in production 
    print "positive hit on the ", positive_idx, " -th columns" 
    put(result, positive_idx, True) 
    idx = setdiff1d(idx, positive_idx) 
    if not idx.size: 
     break 

Чтобы понять, как это работает, мы можем рассмотреть другой вход:

a = np.array([[ 0, 15, 16, 200, 10], 
       [ -1, 10, 17, 11, -1], 
       [ 1, -1, 20, -1, -1]]) 

g = np.array([[ 1, 12, 15, 100, 11], 
       [ 2, 13, 16, 200, 12], 
       [ 3, 14, 17, 300, 13], 
       [ 4, 17, 18, 400, 14], 
       [ 5, 20, 19, 500, 16]]) 

Выход сценария:

1 line, I look only at columns [0 1 2 3 4] 
positive hit on the [2 3] -th columns 
2 line, I look only at columns [0 1 4] 
positive hit on the [] -th columns 
3 line, I look only at columns [0 1 4] 
positive hit on the [0] -th columns 

В принципе вы можете увидеть, как во 2-й и В третьем раунде цикла вы не обрабатываете 2-й и 4-й столбцы.

Производительность этого решения действительно зависит от многих факторов, но это будет быстрее, если вы, вероятно, нажмете много значений True, и проблема имеет много строк. Это, конечно, зависит также от ввода, а не только от формы.

Смежные вопросы