2013-08-07 3 views
2

Мне нужно определить, находится ли позиция (индекс) из k наибольших значений в матрице a в том же положении, что и матрица двоичных индикаторов, b ,Python - Найти значения K max в каждой строке одной матрицы и сравнить с двоичной матрицей

import numpy as np 
a = np.matrix([[.8,.2,.6,.4],[.9,.3,.8,.6],[.2,.6,.8,.4],[.3,.3,.1,.8]]) 
b = np.matrix([[1,0,0,1],[1,0,1,1],[1,1,1,0],[1,0,0,1]]) 
print "a:\n", a 
print "b:\n", b 

d = argsort(a) 
d[:,2:] # Return whether these indices are in 'b' 

Возвращает:

a: 
[[ 0.8 0.2 0.6 0.4] 
[ 0.9 0.3 0.8 0.6] 
[ 0.2 0.6 0.8 0.4] 
[ 0.3 0.3 0.1 0.8]] 
b: 
[[1 0 0 1] 
[1 0 1 1] 
[1 1 1 0] 
[1 0 0 1]] 

matrix([[2, 0], 
     [2, 0], 
     [1, 2], 
     [1, 3]]) 

Я хотел бы сравнить индексы вернулись из последнего результата и, если b имеет одни в этих позициях, возвращает количество. Для этого примера, конечный желаемый результат был бы:

1 
2 
2 
1 

Другими словами, в первом ряду a, топ-2 значения соответствуют только одному из них в b и т.д.

Любые идеи, как это сделать эффективно? Может быть, аргумент здесь неправильный подход. Спасибо.

ответ

0

В ответ на огромную помощь Сауло я смог взять его работу и сократить решение до трех линий. Спасибо, Саулло!

#Inputs 
k = 2 
a = np.matrix([[.8,.2,.6,.4],[.9,.3,.8,.6],[.2,.6,.8,.4],[.3,.3,.1,.8]]) 
b = np.matrix([[1,0,0,1],[1,0,1,1],[1,1,1,0],[1,0,0,1]]) 
print "a:\n", a 
print "b:\n", b 

# Return values of interest 
s = argsort(a.view(np.ndarray), axis=1)[:,::-1] 
s2 = s + (arange(s.shape[0])*s.shape[1])[:,None] 
out = take(b,s2).view(np.ndarray)[::,:k].sum(axis=1) 
print out 

Дает:

a: 
[[ 0.8 0.2 0.6 0.4] 
[ 0.9 0.3 0.8 0.6] 
[ 0.2 0.6 0.8 0.4] 
[ 0.3 0.3 0.1 0.8]] 
b: 
[[1 0 0 1] 
[1 0 1 1] 
[1 1 1 0] 
[1 0 0 1]] 
Out: 
[1 2 2 1] 
1

Когда вы берете argsort вы получите от минимального 0 до максимального 3, так что вы можете отменить его делать [::-1], чтобы получить максимальную 0 и минимальной 3:

s = np.argsort(a, axis=1)[:,::-1] 
#array([[0, 2, 3, 1], 
#  [0, 2, 3, 1], 
#  [2, 1, 3, 0], 
#  [3, 1, 0, 2]]) 

Теперь вы можете использовать np.take для получить 0 s, где максимумы и 1 s, где второй-максимумы являются:

s2 = s + (np.arange(s.shape[0])*s.shape[1])[:,None] 
s = np.take(s.flatten(),s2) 
#array([[0, 3, 1, 2], 
#  [0, 3, 1, 2], 
#  [3, 1, 0, 2], 
#  [2, 1, 3, 0]]) 

В b, то 0 значение должно быть заменено на np.nan так, что 0==np.nan дает False:

b = np.float_(b) 
b[b==0] = np.nan 
#array([[ 1., nan, nan, 1.], 
#  [ 1., nan, 1., 1.], 
#  [ 1., 1., 1., nan], 
#  [ 1., nan, nan, 1.]]) 

и последующее сравнение даст вам желаемый результат:

print np.logical_or(s==b-1, s==b).sum(axis=1) 
#[[1] 
# [2] 
# [2] 
# [1]] 

общего случай, к сравнить n самые большие значения a против двоичного кода b:

def check_a_b(a,b,n=2): 
    b = np.float_(b) 
    b[b==0] = np.nan 
    s = np.argsort(a, axis=1)[:,::-1] 
    s2 = s + (np.arange(s.shape[0])*s.shape[1])[:,None] 
    s = np.take(s.flatten(),s2) 
    ans = s==(b-1) 
    for i in range(n-1): 
     ans = np.logical_or(ans, s==b+i) 
    return ans.sum(axis=1) 

Это позволит сделать пару сравнения в logical_or.

+0

Saullo, спасибо за ваш ответ, но работает ваш код, я получаю '[2,2,1,2]' в качестве выхода. Кроме того, я хотел бы обобщить на k> 2. Есть идеи? Благодаря! – zbinsd

+1

@zbinsd Извините! Я обновил ответ ... здесь я забыл положить '[:, :: - 1]', чтобы отменить исходный результат 'argsort' ... –

+0

Saullo, это становится очень близким. Как я могу получить, скажем, топ-3? В конце концов (для большей матрицы, 'a'), нужно вернуть топ-10. Заранее спасибо. – zbinsd

1

Anothen проще и гораздо быстрее, подход, основанный на том, что:

True*1=1, True*0=0, False*0=0, and False*1=0

является:

def check_a_b_new(a,b,n=2): 
    s = np.argsort(a.view(np.ndarray), axis=1)[:,::-1] 
    s2 = s + (np.arange(s.shape[0])*s.shape[1])[:,None] 
    s = np.take(s.flatten(),s2) 
    return ((s < n)*b.view(np.ndarray)).sum(axis=1) 

избежать 0 для np.nan преобразования в и цикл Python for, что делает вещи довольно медленно для большого значения n.

+0

Saullo, это дает: 'matrix ([[5], [5], [6], [5]])' for вход: 'check_a_b_new (a, b, n = 2)' – zbinsd

+1

, поэтому он просто работает, если 'a' и' b' являются массивами ... Я обдумал ответ ... –

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