Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy, why does `x += y` produce a different result than `x = x + y`? [duplicate]

In this case, why does x += y produce a different result than x = x + y?

import numpy as np

x = np.repeat([1], 10)
y = np.random.random(len(x))

x += y
print x
# Output: [1 1 1 1 1 1 1 1 1 1]

x = x + y
print x
# Output: [ 1.50859536  1.31434732  1.15147365  1.76979431  1.64727364
#           1.02372535  1.39335253  1.71878847  1.48823703  1.99458116]
like image 604
user805627 Avatar asked Jun 21 '13 06:06

user805627


2 Answers

Although the linked question explains the general issue, there is a numpy-specific explanation for this particular case. Basically, those answers say "it depends on the type of the variables involved", and what I'm giving below is the explanation for numpy types.

When you do x + y, numpy uses a "lowest common denominator" datatype for the result. Since x is int and y is float, this means it returns a float array.

But when you do x += y, you are forcing it to conform to the dtype of x, which is int. This truncates the decimal portion and leaves all x values back at 1. This is the way numpy defines the augmented assignment operators: it forces the return value to be of the same dtype as the assignment target.

You can get the first behavior from the second example by doing x = (x + y).astype(int) (explicitly forcing the dtype back to int). You can get the second behavior from the first example by letting x = np.repeat([1.0], 10) (using a float makes x have dtype float, so now you can add y to it without truncation).

like image 94
BrenBarn Avatar answered Oct 04 '22 17:10

BrenBarn


This is due to the difference between __add__ and __iadd__ methods

However usually the difference is seen between mutable vs immutable objects

>>> x = np.repeat([1], 10)
>>> y = np.random.random(len(x))
>>> x += y
>>> x
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])

contrast with

>>> x = np.repeat([1.0], 10)
>>> x += y
>>> x
array([ 1.05192255,  1.00844068,  1.27569982,  1.40997015,  1.17270114,
        1.27335121,  1.70719855,  1.72778867,  1.64679031,  1.23241938])

so __iadd__ is causing the addition to be truncated back to int when x is int type

This makes sense if you think about it - x can't magically change the type of it's elements (where would it store those extra bytes)

for __add__ there is no problem producting a new array of floats instead of ints

like image 41
John La Rooy Avatar answered Oct 04 '22 15:10

John La Rooy