5

this is a somewhat basic question from a beginner Numpy user: I have a 2D array of say 5 rows and 2 columns, you can see that as 10 2d-vectors, and I want to test if a given vector is inside the table.

For example :

>>> tableau = array(range(10), dtype = uint8)
>>> tableau.shape = (5,2)
>>> print tableau
[[ 0  1]
 [ 2  3]
 [ 4  5]
 [ 6  7]
 [ 8  9]]
>>> [0, 1] in tableau
True

Last line gives True, but '[0, 2] in tableau' too.

For the moment, I compute if euclidean distance is 0, but I'm sure there's a simpler answer.

Thanks for any help

Junuxx
  • 14,011
  • 5
  • 41
  • 71
Fred
  • 901
  • 1
  • 8
  • 16
  • Seems to be a duplicate of [this question](http://stackoverflow.com/questions/7100242/python-numpy-first-occurrence-of-subarray). – Junuxx Feb 25 '13 at 13:37
  • @Junuxx That's a different question, here the vector must (apparently) match an entire row. – Janne Karila Feb 25 '13 at 13:47
  • @Janne: What makes you think that? The example might have a vector that is as long as the matrix is wide, but question clearly says "I want to test if a given vector is inside the table" which is more general. – Junuxx Feb 25 '13 at 13:48
  • 1
    @Junuxx The example makes me think that. – Janne Karila Feb 25 '13 at 13:52

3 Answers3

5

You can perform boolean reduction on the match array:

([0, 1] == tableau).all(axis=1).any()
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • @Junuxx it does for me; what are you testing against? – ecatmur Feb 25 '13 at 13:50
  • @Junuxx that's the wrong shape; it should be length 3. `[0, 1, 2]` works; it depends how you're interpreting extending the question. – ecatmur Feb 25 '13 at 14:04
  • @ecatmur: Yes, it seems I interpreted the question (and "subarray") differently, the question could have been clearer. Asker seems happy though, so this must be right, +1. – Junuxx Feb 25 '13 at 14:06
  • 1
    I'm happy indeed :) I agree the question is ambiguous, sorry for that. – Fred Feb 25 '13 at 14:10
  • I posted another answer that builds on yours. – David Jun 18 '14 at 21:53
1

Straight forward, you could use any() to go through a generator comparing the arrays with array_equal.

from numpy import array_equal

in_t = lambda x, t : any((array_equal(a,x) for a in t))

print in_t([0, 2], tableau)
print in_t([0, 1], tableau)
MeisenBar
  • 54
  • 7
0

I wrote a function to solve this that also handles multidimensional cases. (@ecatmur's answer works perfectly in two dimensions, but fails for 1D or 3D+)

import numpy as np
def haselement(arr,subarr):
    '''Test if subarr is equal to one of the elements of arr.
       This is the equivalent of the "in" operator when using lists instead of arrays.'''
    arr = np.asarray(arr)
    subarr = np.asarray(subarr)
    if subarr.shape!=arr.shape[1:]:
        return False
    elif arr.ndim<2:
        return (subarr==arr).any()
    else:
        boolArr = (subarr==arr)
        boolArr.resize([arr.shape[0],np.prod(arr.shape[1:])])
        return boolArr.all(axis=1).any()

tableau = np.array(range(10), dtype = np.uint8)
tableau.shape = (5,2)
haselement(tableau,[0,1])

1D is handled with an if statement, and ND is handled by resizing the array to 2D so that @ecatmur's algorithm will work. The other ways I thought of to solve this involved list comprehensions or loops (which could actually be more efficient but only if the list is long and the element is near the beginning); still, this seems more numpy-thonic.

You can also find the function here if you'd rather use it from a library:

https://github.com/davidmashburn/np_utils (obvious disclaimer, I am the author ;) )

David
  • 328
  • 4
  • 10
  • By the way, does haselement(arr,subarr) or elementof(subarr,arr) make more sense to people? Thanks. – David Jun 18 '14 at 22:02