Reputation: 1839
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
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