kungphil
kungphil

Reputation: 1839

scipy.ndimage.generic_filter returns Type Error

I am using the scipy.ndimage.generic_filter to calculate localised modal values of an array. I was comparing two methods to see which is faster (as the first approach is quite slow). My first approach is;

import numpy as np
import scipy.stats as stats
import scipy.ndimage

def modal(arr):
    return stats.mode(arr, axis=None)[0][0]

x = np.random.randint(0, 100, size=(10, 10))
scipy.ndimage.filters.generic_filter(x, modal, size=3)

My second approach is;

def modal(arr):
    return np.argmax(np.bincount(arr.flatten()))

x = np.random.randint(0, 100, size=(10, 10))
scipy.ndimage.filters.generic_filter(x, modal, size=3)

But with the second approach I get this:

TypeError                                 Traceback (most recent call last)
<ipython-input-122-2e9030c57d71> in <module>()
      1 #%timeit -n 5 -r 1
----> 2 scipy.ndimage.filters.generic_filter(x, modal, size=3)

C:\Python27\ArcGIS10.2\lib\site-packages\scipy\ndimage\filters.pyc in generic_filter(input, function, size, footprint, output, mode, cval, origin, extra_arguments, extra_keywords)
   1161     mode = _ni_support._extend_mode_to_code(mode)
   1162     _nd_image.generic_filter(input, function, footprint, output, mode,
-> 1163                          cval, origins, extra_arguments, extra_keywords)
   1164     return return_value

<ipython-input-118-86ea9b03ed30> in modal(arr)
      1 def modal(arr):
----> 2     return np.argmax(np.bincount(arr.flatten()))
      3     return stats.mode(arr, axis=None)[0][0]

TypeError: array cannot be safely cast to required type

When I run this:

stats.mode(x, axis=None)[0][0] == np.argmax(np.bincount(x.flatten()))

It returns True

Why does the generic_filter throw the type error when using the numpy.bincount method and not the stats.mode method when the returned value is the same?

I am using Python 2.7.3, Numpy 1.6.1 and Scipy 0.14.0 on Windows 7 (I am stuck to this version of Numpy and Python as this is what ships with ESRI ArcGIS). I tried installing scikit-image to calculate the modal filter but I got other errors on install and thought it simpler to resolve this one!

Upvotes: 0

Views: 869

Answers (1)

unutbu
unutbu

Reputation: 879451

You can investigate this error by putting a print statement in modal:

def modal(arr):
    print(arr)
    return np.argmax(np.bincount(arr.flatten()))

You'll see output like

[ 92.  92.  31.  92.  92.  31.  87.  87.  18.]

which shows that arr contains floats, not ints. The documentation for np.bincount states its first argument must be a 1 dimensional array of nonnegative ints.

So, you can avoid the error by using astype('int64') to cast the floats as ints.

import numpy as np
import scipy.stats as stats
import scipy.ndimage

def modal(arr):
    return stats.mode(arr, axis=None)[0][0]

def modal2(arr):
    count = np.bincount(arr.astype('int64'))
    return np.argmax(count)

x = np.random.randint(0, 100, size=(10, 10))

out = np.empty_like(x, dtype='float')
scipy.ndimage.filters.generic_filter(x, modal, size=3, output=out)
print(out)

scipy.ndimage.filters.generic_filter(x, modal2, size=3, output=out)
print(out)

PS. The call to flatten can be removed since arr is already one dimensional.

Upvotes: 2

Related Questions