Arrays on Python with numpy

I have a problem with the floats on my arrays.

    import numpy
from StringIO import StringIO


matrizgeometrica = numpy.loadtxt('geometrica.txt')    # crea la matriz geometrica a partir del txt
matrizvelocidades = numpy.loadtxt('velocidades.txt')    # crea la matriz de velocidades a partir del txt

#Se genera la matriz de tiempos unitarios a partir de la matriz geometrica y la matriz de velocidades
matriztiempo=matrizgeometrica
for x in matriztiempo:
    for y in matriztiempo:
        if matriztiempo[x,y]!=0 and matrizvelocidades[x,y]!=0:
            matriztiempo[x,y]=matriztiempo[x,y]/matrizvelocidades[x,y]
        else:
            matriztiempo[x,y]=0

the error is this:

Traceback (most recent call last):
  File "lpi2.py", line 12, in <module>
    if matriztiempo[x,y]!=0 and matrizvelocidades[x,y]!=0:
IndexError: arrays used as indices must be of integer (or boolean) type

I don't know what the problem is but I can't change the values to integer, I need the floats.

Upvotes: 1

Views: 4148

Answers (1)

steveha
steveha

Reputation: 76695

This is your loop:

for x in matriztiempo:

This will set x to values from the array. This does not find the position of the values; it just gets the values.

If you want to know the position, the best way is to use enumerate() like so:

for i, x in enumerate(matriztiempo):

Now x gets the value as before, but also i gets the index of that value in the list.

I think in your case it might be easiest to write the loop like this:

for x in xrange(matriztiempo.shape[0]):
    for y in xrange(matriztiempo.shape[1]):
        if matrizvelocidades[x,y] != 0:
            matriztiempo[x,y] /= matrizvelocidades[x,y]
        else:
            matriztiempo[x,y] = 0

Usually in Python when we are working with two lists we might want to use zip() or itertools.izip() to get values, but in this case you are rewriting an array in place using two index values, and I think writing it the above way might be best. Certainly it's the simplest.

Note that we don't need to test for matriztiempo[x,y] being equal to zero; if it is, then the result will be zero for any valid divisor. We need to check that the divisor is valid to avoid a divide-by-zero exception. (We could also put a try: / except block to catch this case, if zero is an unlikely value in matrizvelocidades. If it is a likely value, this is a good way to go.

EDIT: But since this is NumPy there is a better way to do this, much faster. If we didn't need to worry about zeros in the divisor, we could simply do this:

matriztiempo /= matrizvelocidades

Since we do need to worry about zeros, we can make a "mask" to solve this.

good_mask = (matrizvelocidades != 0)
bad_mask = numpy.logical_not(good_mask)

matriztiempo[good_mask] /= matrizvelocidades[good_mask]
matriztiempo[bad_mask] = 0.0

This should be tremendously faster than the solution using for loops.

You could also make bad_mask like this:

bad_mask = (matrizvelocidades == 0)

But by explicitly computing numpy.logical_not() we make sure that bad_mask is always the correct logical inverse of good_mask. If someone edits the line that creates good_mask, the numpy.logical_not() will find the correct inverse, but if we just had a second expression referencing matrizvelocidades then editing one but not editing the other would introduce a bug.

Upvotes: 4

Related Questions