2013-05-02 21 views
27

Tam sayı içeren bir 2D dizilim var (hem pozitif hem de negatif). Her satır belirli bir uzamsal alan için zamana göre değerleri temsil ederken, her sütun belirli bir zaman için çeşitli mekansal alanlar için değerleri temsil eder. dizi gibi iseSayısal dizide modu bulmanın en verimli yolu

Böylece:

1 3 4 2 2 7 
5 2 2 1 4 1 
3 3 2 2 1 1 

sonuç modu için birden fazla değer olduğunda, (rastgele seçilmiş) bir bir modu olarak ayarlanmış olabilir

1 3 2 2 2 1 

Not olmalıdır .

Her seferinde bir mod bulma sütunları üzerinde yineleyebilirim, ancak numpy'nin bunu yapmak için bazı yerleşik işlevleri olabileceğini umuyordum. Ya da döngü olmadan verimli bir şekilde bulmak için bir hile varsa. (@ Tom10 yorumuna esinlenerek)

+0

http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mstats.mode.html ve bunun cevabı burada bulunmaktadır: http://stackoverflow.com/questions/6252280/find - en sık-sayı-in-a-numpy-vektör – tom10

+1

@ tom10: [scipy.stats.mode()] demek istediniz (http: //docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mode.html # scipy.stats.mode), değil mi? Diğeri maskeli bir dizi çıktı gibi görünüyor. – fgb

+0

@fgb: Doğru, düzeltme için teşekkürler (ve cevabınız için +1). – tom10

cevap

52

Kontrol scipy.stats.mode():

import numpy as np 
from scipy import stats 

a = np.array([[1, 3, 4, 2, 2, 7], 
       [5, 2, 2, 1, 4, 1], 
       [3, 3, 2, 2, 1, 1]]) 

m = stats.mode(a) 
print(m) 

Çıktı: Gördüğünüz gibi

ModeResult(mode=array([[1, 3, 2, 2, 1, 1]]), count=array([[1, 2, 2, 2, 1, 2]])) 

, her iki döner modu yanı sıra sayar. Sen m[0] üzerinden doğrudan modları seçebilirsiniz:

print(m[0]) 

Çıktı:

[[1 3 2 2 1 1]] 
+3

Bu yüzden, tek başına numpy herhangi bir işlevi desteklemiyor mu? – Nik

+1

Görünüşe göre değil, ama [Scipi'nin uygulaması sadece uyuşmaya dayanıyor] (http://stackoverflow.com/questions/12399107/alternative-to-scipy-mode-function-in-numpy), böylece bu kodu sadece kendi işlevi. – fgb

+5

Sadece bir not, gelecekte buna bakmak isteyenler için: "scipy.stats" dosyasını içe aktarmanız gerekiyor, sadece bir "import scipy" işlemi yaptığınızda dahil edilmiyor. – ffledgling

10

Bu zor bir problemdir, bir eksen boyunca modu hesaplamak için çok orada olmadığından. Çözüm, numpy.bincount'un numpy.unique ile birlikte return_counts arg ile True olarak kullanıldığı 1-D dizileri için düzdür. Gördüğüm en yaygın n-boyutlu işlev scipy.stats.mode'dur, ancak özellikle de birçok benzersiz değere sahip büyük diziler için yavaştır. Bir çözüm olarak, ben bu fonksiyonu geliştirmiştir ve ağır kullanmak:

import numpy 

def mode(ndarray, axis=0): 
    # Check inputs 
    ndarray = numpy.asarray(ndarray) 
    ndim = ndarray.ndim 
    if ndarray.size == 1: 
     return (ndarray[0], 1) 
    elif ndarray.size == 0: 
     raise Exception('Cannot compute mode on empty array') 
    try: 
     axis = range(ndarray.ndim)[axis] 
    except: 
     raise Exception('Axis "{}" incompatible with the {}-dimension array'.format(axis, ndim)) 

    # If array is 1-D and numpy version is > 1.9 numpy.unique will suffice 
    if all([ndim == 1, 
      int(numpy.__version__.split('.')[0]) >= 1, 
      int(numpy.__version__.split('.')[1]) >= 9]): 
     modals, counts = numpy.unique(ndarray, return_counts=True) 
     index = numpy.argmax(counts) 
     return modals[index], counts[index] 

    # Sort array 
    sort = numpy.sort(ndarray, axis=axis) 
    # Create array to transpose along the axis and get padding shape 
    transpose = numpy.roll(numpy.arange(ndim)[::-1], axis) 
    shape = list(sort.shape) 
    shape[axis] = 1 
    # Create a boolean array along strides of unique values 
    strides = numpy.concatenate([numpy.zeros(shape=shape, dtype='bool'), 
           numpy.diff(sort, axis=axis) == 0, 
           numpy.zeros(shape=shape, dtype='bool')], 
           axis=axis).transpose(transpose).ravel() 
    # Count the stride lengths 
    counts = numpy.cumsum(strides) 
    counts[~strides] = numpy.concatenate([[0], numpy.diff(counts[~strides])]) 
    counts[strides] = 0 
    # Get shape of padded counts and slice to return to the original shape 
    shape = numpy.array(sort.shape) 
    shape[axis] += 1 
    shape = shape[transpose] 
    slices = [slice(None)] * ndim 
    slices[axis] = slice(1, None) 
    # Reshape and compute final counts 
    counts = counts.reshape(shape).transpose(transpose)[slices] + 1 

    # Find maximum counts and return modals/counts 
    slices = [slice(None, i) for i in sort.shape] 
    del slices[axis] 
    index = numpy.ogrid[slices] 
    index.insert(axis, numpy.argmax(counts, axis=axis)) 
    return sort[index], counts[index] 

Sonuç:

In [2]: a = numpy.array([[1, 3, 4, 2, 2, 7], 
         [5, 2, 2, 1, 4, 1], 
         [3, 3, 2, 2, 1, 1]]) 

In [3]: mode(a) 
Out[3]: (array([1, 3, 2, 2, 1, 1]), array([1, 2, 2, 2, 1, 2])) 

Bazı kriterler:

In [4]: import scipy.stats 

In [5]: a = numpy.random.randint(1,10,(1000,1000)) 

In [6]: %timeit scipy.stats.mode(a) 
10 loops, best of 3: 41.6 ms per loop 

In [7]: %timeit mode(a) 
10 loops, best of 3: 46.7 ms per loop 

In [8]: a = numpy.random.randint(1,500,(1000,1000)) 

In [9]: %timeit scipy.stats.mode(a) 
1 loops, best of 3: 1.01 s per loop 

In [10]: %timeit mode(a) 
10 loops, best of 3: 80 ms per loop 

In [11]: a = numpy.random.random((200,200)) 

In [12]: %timeit scipy.stats.mode(a) 
1 loops, best of 3: 3.26 s per loop 

In [13]: %timeit mode(a) 
1000 loops, best of 3: 1.75 ms per loop 

EDIT: Sağlanan bir arka plan daha Yaklaşımın daha verimli olması için modifiye edilmiş

3

Genişletme this method, appl Değerin, dağıtımın merkezinden ne kadar uzakta olduğunu görmek için gerçek dizinin indeksine ihtiyaç duyabileceğiniz verilerin modunu bulmaya çalışın. len zaman

(_, idx, counts) = np.unique(a, return_index=True, return_counts=True) 
index = idx[np.argmax(counts)] 
mode = a[index] 

bunu, ona standart sapma içine düşüp düşmediğini kontrol edebilir aslında verilerinizin merkezi dağıtım temsili ise de doğrulamak için, 1> (np.argmax (sayımlarını)) modunu iptal etmek hatırla Aralık.