Hilary Chang
Hilary Chang

Reputation: 53

What is the '<' doing in this line?: data += dt < b

Input:

dt    = [6,7,8,9,10]
data  = [1,2,3,4,5]

b     = 8.0
b     = np.require(b, dtype=np.float)

data  += dt  < b
data

Output:

array([2, 3, 3, 4, 5])

I tried to input different number but still couldn't figure out what's the "<" doing there.... Also, it seems to work only when b is np.float (hence the conversion).

Upvotes: 3

Views: 102

Answers (3)

MSeifert
MSeifert

Reputation: 152745

The < with numpy arrays does an element-wise comparison. That means it returns an array where there is a True where the condition is true and False if not. The np.require line is necessary here so it actually uses NumPy arrays. You could drop the np.require if you converted your data and dt to np.arrays beforehand.

Then the result is added (element-wise) to the numeric array. In this context True is equal to 1 and False to zero.

>>> dt < b  # which elements are smaller than b?
array([ True,  True, False, False, False])

>>> 0 + (dt  < b)  # boolean arrays in arithmetic operations with numbers
array([1, 1, 0, 0, 0])

So it adds 1 to every element of data where the element in dt is smaller than 8.

Upvotes: 6

hpaulj
hpaulj

Reputation: 231550

dt is a list:

In [50]: dt    = [6,7,8,9,10]
In [51]: dt < 8
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-51-3d06f93227f5> in <module>()
----> 1 dt < 8

TypeError: '<' not supported between instances of 'list' and 'int'

< (.__lt__) is not defined for lists.

But if one element of the comparison is an ndarray, then the numpy definition of __lt__ applies. dt is turned into an array, and it does an element by element comparison.

In [52]: dt < np.array(8)
Out[52]: array([ True,  True, False, False, False])
In [53]: np.array(dt) < 8
Out[53]: array([ True,  True, False, False, False])

numpy array operations also explain the data += part:

In [54]: data  = [1,2,3,4,5]          # a list
In [55]: data + (dt < np.array(8))    # list=>array, and boolean array to integer array
Out[55]: array([2, 3, 3, 4, 5])
In [56]: data
Out[56]: [1, 2, 3, 4, 5]
In [57]: data += (dt < np.array(8))
In [58]: data
Out[58]: array([2, 3, 3, 4, 5])

Actually I'm a bit surprised that with the += data has been changed from list to array. It means the data+=... has been implemented as an assignment:

data = data + (dt <np.array(8))

Normally + for a list is a concatenate:

In [61]: data += ['a','b','c']
In [62]: data
Out[62]: [1, 2, 3, 4, 5, 'a', 'b', 'c']
# equivalent of: data.extend(['a','b','c'])

You can often get away with using lists in array contexts, but it's better to make objects arrays, so you do get these implicit, and sometimes unexpected, conversions.

Upvotes: 2

kmario23
kmario23

Reputation: 61445

This is just an alias (or shortcut or convenience notation) to the equivalent function: numpy.less()

In [116]: arr1 = np.arange(8)
In [117]: scalar = 6.0

# comparison that generates a boolean mask
In [118]: arr1 < scalar
Out[118]: array([ True,  True,  True,  True,  True,  True, False, False])

# same operation as above 
In [119]: np.less(arr1, scalar)
Out[119]: array([ True,  True,  True,  True,  True,  True, False, False])

Let's see how this boolean array can be added to a non-boolean array in this case. It is possible due to type coercion

# sample array
In [120]: some_arr = np.array([1, 1, 1, 1, 1, 1, 1, 1])

# addition after type coercion 
In [122]: some_arr + (arr1 < scalar)
Out[122]: array([2, 2, 2, 2, 2, 2, 1, 1])

# same output achieved with `numpy.less()`
In [123]: some_arr + np.less(arr1, scalar)
Out[123]: array([2, 2, 2, 2, 2, 2, 1, 1])

So, type coercion happens on the boolean array and then addition is performed.

Upvotes: 1

Related Questions