it-swarm.com.de

numpy: effizienteste Frequenzzählung für eindeutige Werte in einem Array

Gibt es innumpy/ - scipyeinen effizienten Weg, Frequenzzählungen für eindeutige Werte in einem Array zu erhalten?

Etwas in diese Richtung:

x = array( [1,1,1,2,2,2,5,25,1,1] )
y = freq_count( x )
print y

>> [[1, 5], [2,3], [5,1], [25,1]]

(Für Sie, R-Nutzer da draußen, suche ich grundsätzlich die Funktion table())

162
Abe

Schau dir np.bincount an:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.bincount.html

import numpy as np
x = np.array([1,1,1,2,2,2,5,25,1,1])
y = np.bincount(x)
ii = np.nonzero(y)[0]

Und dann:

Zip(ii,y[ii]) 
# [(1, 5), (2, 3), (5, 1), (25, 1)]

oder:

np.vstack((ii,y[ii])).T
# array([[ 1,  5],
         [ 2,  3],
         [ 5,  1],
         [25,  1]])

oder wie Sie die Zählwerte und die eindeutigen Werte kombinieren möchten.

118
JoshAdel

Ab Numpy 1.9 ist die einfachste und schnellste Methode die Verwendung von numpy.unique , das jetzt ein Schlüsselwort return_counts hat:

import numpy as np

x = np.array([1,1,1,2,2,2,5,25,1,1])
unique, counts = np.unique(x, return_counts=True)

print np.asarray((unique, counts)).T

Was gibt:

 [[ 1  5]
  [ 2  3]
  [ 5  1]
  [25  1]]

Ein schneller Vergleich mit scipy.stats.itemfreq:

In [4]: x = np.random.random_integers(0,100,1e6)

In [5]: %timeit unique, counts = np.unique(x, return_counts=True)
10 loops, best of 3: 31.5 ms per loop

In [6]: %timeit scipy.stats.itemfreq(x)
10 loops, best of 3: 170 ms per loop
360
jme

Update: Die in der ursprünglichen Antwort erwähnte Methode ist veraltet, wir sollten stattdessen die neue Methode verwenden:

>>> import numpy as np
>>> x = [1,1,1,2,2,2,5,25,1,1]
>>> np.array(np.unique(x, return_counts=True)).T
    array([[ 1,  5],
           [ 2,  3],
           [ 5,  1],
           [25,  1]])

Ursprüngliche Antwort:

sie können scipy.stats.itemfreq verwenden.

>>> from scipy.stats import itemfreq
>>> x = [1,1,1,2,2,2,5,25,1,1]
>>> itemfreq(x)
/usr/local/bin/python:1: DeprecationWarning: `itemfreq` is deprecated! `itemfreq` is deprecated and will be removed in a future version. Use instead `np.unique(..., return_counts=True)`
array([[  1.,   5.],
       [  2.,   3.],
       [  5.,   1.],
       [ 25.,   1.]])
107
McKelvin

Ich war auch daran interessiert, also habe ich einen kleinen Leistungsvergleich gemacht (mit perfplot , einem meiner Lieblingsprojekte). Ergebnis:

 y = np.bincount(a)
 ii = np.nonzero(y)[0]
 out = np.vstack((ii, y[ii])).T

ist bei weitem der schnellste. (Beachten Sie die Protokollskalierung.)

 enter image description here


Code zum Erzeugen des Diagramms:

import numpy as np
import pandas as pd
import perfplot
from scipy.stats import itemfreq


def bincount(a):
    y = np.bincount(a)
    ii = np.nonzero(y)[0]
    return np.vstack((ii, y[ii])).T


def unique(a):
    unique, counts = np.unique(a, return_counts=True)
    return np.asarray((unique, counts)).T


def unique_count(a):
    unique, inverse = np.unique(a, return_inverse=True)
    count = np.zeros(len(unique), np.int)
    np.add.at(count, inverse, 1)
    return np.vstack((unique, count)).T


def pandas_value_counts(a):
    out = pd.value_counts(pd.Series(a))
    out.sort_index(inplace=True)
    out = np.stack([out.keys().values, out.values]).T
    return out


perfplot.show(
    setup=lambda n: np.random.randint(0, 1000, n),
    kernels=[bincount, unique, itemfreq, unique_count, pandas_value_counts],
    n_range=[2**k for k in range(26)],
    logx=True,
    logy=True,
    xlabel='len(a)'
    )
27
Nico Schlömer

Pandas-Modul verwenden:

>>> import pandas as pd
>>> import numpy as np
>>> x = np.array([1,1,1,2,2,2,5,25,1,1])
>>> pd.value_counts(pd.Series(x))
1     5
2     3
25    1
5     1

dtype: int64

21
ivankeller

Dies ist bei weitem die allgemeinste und leistungsfähigste Lösung; überrascht, dass es noch nicht veröffentlicht wurde.

import numpy as np

def unique_count(a):
    unique, inverse = np.unique(a, return_inverse=True)
    count = np.zeros(len(unique), np.int)
    np.add.at(count, inverse, 1)
    return np.vstack(( unique, count)).T

print unique_count(np.random.randint(-10,10,100))

Im Gegensatz zu der aktuell akzeptierten Antwort funktioniert sie für jeden sortierbaren Datentyp (nicht nur für positive Ints) und bietet eine optimale Leistung. Der einzige bedeutende Aufwand ist die Sortierung durch np.unique.

17

numpy.bincount ist wahrscheinlich die beste Wahl. Wenn Ihr Array außer kleinen, dichten Ganzzahlen etwas enthält, kann es nützlich sein, es in etwa wie folgt einzuhüllen:

def count_unique(keys):
    uniq_keys = np.unique(keys)
    bins = uniq_keys.searchsorted(keys)
    return uniq_keys, np.bincount(bins)

Zum Beispiel:

>>> x = array([1,1,1,2,2,2,5,25,1,1])
>>> count_unique(x)
(array([ 1,  2,  5, 25]), array([5, 3, 1, 1]))
14
Bi Rico

Obwohl dies bereits beantwortet wurde, schlage ich einen anderen Ansatz vor, der numpy.histogram verwendet. Eine solche Funktion gibt bei einer Sequenz die Häufigkeit ihrer Elemente gruppiert in Bins zurück.

Achtung: In diesem Beispiel funktioniert es, weil Zahlen Ganzzahlen sind. Wenn sie reelle Zahlen waren, würde diese Lösung nicht so gut zutreffen.

>>> from numpy import histogram
>>> y = histogram (x, bins=x.max()-1)
>>> y
(array([5, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       1]),
 array([  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,
        12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.,  21.,  22.,
        23.,  24.,  25.]))
7
Jir
import pandas as pd
import numpy as np
x = np.array( [1,1,1,2,2,2,5,25,1,1] )
print(dict(pd.Series(x).value_counts()))

Dies gibt Ihnen: {1: 5, 2: 3, 5: 1, 25: 1}

4
Kerem T

Alte Frage, aber ich möchte meine eigene Lösung bereitstellen, die sich als die schnellste herausstellt. Verwenden Sie normallistanstelle von np.array als Eingabe (oder übertragen Sie zuerst auf die Liste), basierend auf meinem Test.

Schau es dir an wenn du es auch findest.

def count(a):
    results = {}
    for x in a:
        if x not in results:
            results[x] = 1
        else:
            results[x] += 1
    return results

Zum Beispiel, 

>>>timeit count([1,1,1,2,2,2,5,25,1,1]) would return:

100000 Loops, am besten von 3: 2,26 µs pro Loop

>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]))

100000 Loops, am besten von 3: 8,8 µs pro Loop

>>>timeit count(np.array([1,1,1,2,2,2,5,25,1,1]).tolist())

100000 Loops, am besten von 3: 5,85 µs pro Loop

Die akzeptierte Antwort wäre zwar langsamer und die scipy.stats.itemfreq-Lösung ist noch schlimmer.


Eine eingehendere Prüfung bestätigte nicht die formulierte Erwartung.

from zmq import Stopwatch
aZmqSTOPWATCH = Stopwatch()

aDataSETasARRAY = ( 100 * abs( np.random.randn( 150000 ) ) ).astype( np.int )
aDataSETasLIST  = aDataSETasARRAY.tolist()

import numba
@numba.jit
def numba_bincount( anObject ):
    np.bincount(    anObject )
    return

aZmqSTOPWATCH.start();np.bincount(    aDataSETasARRAY );aZmqSTOPWATCH.stop()
14328L

aZmqSTOPWATCH.start();numba_bincount( aDataSETasARRAY );aZmqSTOPWATCH.stop()
592L

aZmqSTOPWATCH.start();count(          aDataSETasLIST  );aZmqSTOPWATCH.stop()
148609L

Ref. Kommentare zu Cache und anderen In-RAM-Nebeneffekten, die einen kleinen Datensatz massiv repetitive Testergebnisse beeinflussen.

4
Rain Lee

Um - eindeutige Nicht-Ganzzahlen zu zählen ähnlich der Antwort von Eelco Hoogendoorn, aber wesentlich schneller (Faktor 5 auf meinem Rechner), habe ich weave.inline verwendet, um numpy.unique mit etwas C-Code zu kombinieren; 

import numpy as np
from scipy import weave

def count_unique(datain):
  """
  Similar to numpy.unique function for returning unique members of
  data, but also returns their counts
  """
  data = np.sort(datain)
  uniq = np.unique(data)
  nums = np.zeros(uniq.shape, dtype='int')

  code="""
  int i,count,j;
  j=0;
  count=0;
  for(i=1; i<Ndata[0]; i++){
      count++;
      if(data(i) > data(i-1)){
          nums(j) = count;
          count = 0;
          j++;
      }
  }
  // Handle last value
  nums(j) = count+1;
  """
  weave.inline(code,
      ['data', 'nums'],
      extra_compile_args=['-O2'],
      type_converters=weave.converters.blitz)
  return uniq, nums

Profil Information

> %timeit count_unique(data)
> 10000 loops, best of 3: 55.1 µs per loop

Eelcos reine numpy-Version: 

> %timeit unique_count(data)
> 1000 loops, best of 3: 284 µs per loop

Hinweis

Hier gibt es Redundanz (unique führt auch eine Sortierung durch), was bedeutet, dass der Code möglicherweise weiter optimiert werden könnte, indem die unique-Funktionalität in die C-Code-Schleife eingefügt wird. 

2
jmetz

so etwas sollte es tun:

#create 100 random numbers
arr = numpy.random.random_integers(0,50,100)

#create a dictionary of the unique values
d = dict([(i,0) for i in numpy.unique(arr)])
for number in arr:
    d[j]+=1   #increment when that value is found

Auch dieser vorherige Post zum Effizientes Zählen einzigartiger Elemente scheint Ihrer Frage ziemlich ähnlich zu sein, es sei denn, mir fehlt etwas.

1
benjaminmgross

mehrdimensionale Frequenzzählung, d.h. Arrays zählen.

>>> print(color_array    )
  array([[255, 128, 128],
   [255, 128, 128],
   [255, 128, 128],
   ...,
   [255, 128, 128],
   [255, 128, 128],
   [255, 128, 128]], dtype=uint8)


>>> np.unique(color_array,return_counts=True,axis=0)
  (array([[ 60, 151, 161],
    [ 60, 155, 162],
    [ 60, 159, 163],
    [ 61, 143, 162],
    [ 61, 147, 162],
    [ 61, 162, 163],
    [ 62, 166, 164],
    [ 63, 137, 162],
    [ 63, 169, 164],
   array([     1,      2,      2,      1,      4,      1,      1,      2,
         3,      1,      1,      1,      2,      5,      2,      2,
       898,      1,      1,  
0
vishal

pandas als pd importieren

importiere numpy als np

pd.Series (name_of_array) .value_counts ()

0
RAJAT BHATHEJA