Karan
Karan

Reputation: 35

Using np.where with OOP

I have create an numpy array in which all the cells values are objects. I want to use np.where conditions but it is not working as I want to check the equivalent conditions for object attributes. The object class looks similar to the one below:

class Cell():
     def __init__(self):
         self.value = 'ABC'
     def __repr__(self):
         return self.value

Now I have 2D numpy array with all the cell equivalent to this cell class, and I want to check if cell.value == 'ABC'. The numpy array look like,

array([[M, M, M, M],
       [M, 'ABC', M, M],
       [M, M, M, M],
       [M, M, M, 'ABC'],
       [M, M, M, M]], dtype=object)

If I try to run np.where(temp == 'ABC'), I get the following output:

(array([], dtype=int64), array([], dtype=int64))

And if I run the command np.where(temp.value == 'ABC'), I get the following error:

AttributeError                            Traceback (most recent call last)
<ipython-input-70-073cbaaed538> in <module>
----> 1 np.where(temp.value =='ABC')

AttributeError: 'numpy.ndarray' object has no attribute 'value'

How can I use np.where with OOP?

Upvotes: 1

Views: 506

Answers (3)

Akshay Sehgal
Akshay Sehgal

Reputation: 19332

You are comparing with an object ('ABC') from str class with an object from '__main__.Cell' class. (try checking with type(Cell())

A fix is simply changing type with np.array.astype()

arr = np.array([['M', Cell(),'M'], 
                ['M', Cell(),'M'], 
                [Cell(),'M' ,'M']])

np.where(arr.astype(str)=='ABC')
(array([0, 1, 2]), array([1, 1, 0]))

Additionally,

You can check type of each element individually in your array by -

np.vectorize(type)(arr)
array([[<class 'str'>, <class '__main__.Cell'>, <class 'str'>],
       [<class 'str'>, <class '__main__.Cell'>, <class 'str'>],
       [<class '__main__.Cell'>, <class 'str'>, <class 'str'>]],
      dtype=object)

Notice, that some of them are objects of class str which you want to use for comparison but others are Cell class objects.

Upvotes: 2

hpaulj
hpaulj

Reputation: 231530

In [38]: class Cell():
    ...:      def __init__(self):
    ...:          self.value = 'ABC'
    ...:      def __repr__(self):
    ...:          return self.value
    ...: 

A list of these objects:

In [39]: alist = [Cell(),Cell(),Cell()]
In [40]: [c.value for c in alist]
Out[40]: ['ABC', 'ABC', 'ABC']
In [41]: alist.value
Traceback (most recent call last):
  File "<ipython-input-41-e136813b0fd2>", line 1, in <module>
    alist.value
AttributeError: 'list' object has no attribute 'value'

An array of the same:

In [42]: arr = np.array(alist)
In [43]: arr
Out[43]: array([ABC, ABC, ABC], dtype=object)
In [44]: arr.value
Traceback (most recent call last):
  File "<ipython-input-44-bfedc572e969>", line 1, in <module>
    arr.value
AttributeError: 'numpy.ndarray' object has no attribute 'value'

Same problem as with this list. Just because the elements have some attribute, it does not mean that a list or array has that attribute. That's not how Python's OOP works.

In [45]: [c.value for c in arr]
Out[45]: ['ABC', 'ABC', 'ABC']

An alternative to the list comprehension:

In [46]: np.frompyfunc(lambda x: x.value, 1,1)(arr)
Out[46]: array(['ABC', 'ABC', 'ABC'], dtype=object)

This may be convenient in some cases, but it is not faster.

Upvotes: 0

Karan
Karan

Reputation: 125

I think you need to traverse through the whole array to check if something is equal to 'ABC'. The code for the same is below:

m =[]
for i in range(temp.shape[0]):
    m.append([])
    for j in range(temp.shape[1]):
        m[i].append(temp[i,j].value == 'ABC')
np.where(m)

In this case, you won't have the computation advantage of using np.where, as you need to traverse through the whole array using for loops.

Upvotes: 0

Related Questions