3

Suppose you have this array:

In [29]: a = array([[10, 20, 30, 40, 50], [14, 28, 42, 56, 70], [18, 36, 54, 72, 90]])

Out[30]: a
array([[ 0,  0,  0,  0,  0],
       [14, 28, 42, 56, 70],
       [18, 36, 54, 72, 90]])

Now divide the third row by the first one (using from future import division)

In [32]: a[0]/a[2]
Out[32]: array([ 0.55555556,  0.55555556,  0.55555556,  0.55555556,  0.55555556])

Now do the same with each row in a loop:

In [33]: for i in range(3):
            print a[i]/a[2]   
[ 0.55555556  0.55555556  0.55555556  0.55555556  0.55555556]
[ 0.77777778  0.77777778  0.77777778  0.77777778  0.77777778]
[ 1.  1.  1.  1.  1.]

Everything looks right. But now, assign the first array a[i]/a[2] to a[i]:

In [35]: for i in range(3):
            a[i]/=a[2]
   ....:     

In [36]: a
Out[36]: 
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1]])

Alright, no problem. Turns out this is by design. Instead, we should do:

In [38]: for i in range(3):
            a[i] = a[i]/a[2]
   ....:     

In [39]: a
Out[39]: 
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1]])

But that doesn't work. Why and how can I fix it?

Thanks in advance.

0

3 Answers 3

6

You can cast the whole array to a float array first:

a = a.astype('float')
a /= a[2]
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks. Yes, I thought about that but I was wondering about a solution involving the division since it should work as a[i] = a[i]/a[2]
In case it's not obvious, this creates a new array. There is no way (that I know of) to do it that modifies the old array in place and changes the type.
It's not possible to do in general since the old and new types may have different sizes, or the old array might be a view into some other array that shouldn't be modified.
@nneonneo -- true -- sort of. From a python API perspective, that doesn't matter. ndarray is a wrapper around a c-array (data). In principle, you could just move the pointer that your ndarray has to a new block of data and from a python perspective, you did the operation "in place". e.g. a = array(...); b = a; a.magic_type_convert(float); b.dtype is a.dtype #true. But, I don't know if that operation exists. And provided that views are holding the same reference to the data (and I think they are), that would work too.
@mgilson Actually, I hadn't considered that. However, numpy arrays are still mutable c = array([1]); id(c) returns 32610992. Then c[0] = 2 changes the array to array([2]) and id(c) still returns 32610992, so I thought it could be doing the same by row.
|
4

"Why doesn't this work" -- The reason it doesn't work is because numpy arrays have a datatype when they're created. Any attempt to put a different type into that array will be cast to the appropriate type. In other words, when you try to put a float into your integer array, numpy casts the float to an int. The reasoning behind this is because numpy arrays are designed to be a homogonous type in order for them to have optimal performance. Put another way, they're implemented as arrays in C. And in C, you can't have an array where 1 element is a float and the next is an int. (You can have structs which behave like that, but they're not arrays).

Another solution (in addition to the one proposed by @nneonneo) is to specify the array as a float array from the beginning:

a = array([[10, 20, 30, 40, 50], [14, 28, 42, 56, 70], [18, 36, 54, 72, 90]], dtype=float)

2 Comments

Right. Yes, you're absolutely right as a.dtype returns dtype('int64') Then once an array is created, unless explicitly changed, it keeps its data type. Is that it?
@RobertSmith -- It keeps it's data type no matter what. You can't explicitly change the data type. Doing a.astype(float) actually creates a new ndarray which is of type float.
3

It's not the division that's the issue it's the assignment, ie a[i] = ... (which is also used behind the scene when you do a /= ...). Try this:

>>> a = np.zeros(3, dtype='uint8')
>>> a[:] = [2, -3, 5.9]
>>> print a
[  2 253   5]

When you do intarray[i] = floatarray[i] numpy has to truncate the floating point values to get them to fit into intarray.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.