Angenommen, ich habe die folgende Liste in Python:
a = [1,2,3,1,2,1,1,1,3,2,2,1]
Wie finde ich die häufigste Nummer in dieser Liste auf übersichtliche Weise?
Angenommen, ich habe die folgende Liste in Python:
a = [1,2,3,1,2,1,1,1,3,2,2,1]
Wie finde ich die häufigste Nummer in dieser Liste auf übersichtliche Weise?
Antworten:
Wenn Ihre Liste alle nicht negativen Ints enthält, sollten Sie sich numpy.bincounts ansehen:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.bincount.html
und dann wahrscheinlich np.argmax verwenden:
a = np.array([1,2,3,1,2,1,1,1,3,2,2,1])
counts = np.bincount(a)
print np.argmax(counts)
Für eine kompliziertere Liste (die möglicherweise negative Zahlen oder nicht ganzzahlige Werte enthält) können Sie sie np.histogram
auf ähnliche Weise verwenden. Wenn Sie nur in Python arbeiten möchten, ohne numpy zu verwenden, collections.Counter
ist dies eine gute Möglichkeit, mit dieser Art von Daten umzugehen .
from collections import Counter
a = [1,2,3,1,2,1,1,1,3,2,2,1]
b = Counter(a)
print b.most_common(1)
scipy.stats.mode
, wenn auch weniger allgemein.
Counter(array).most_common(1)[0][0]
Sie können verwenden
(values,counts) = np.unique(a,return_counts=True)
ind=np.argmax(counts)
print values[ind] # prints the most frequent element
Wenn ein Element so häufig ist wie ein anderes, gibt dieser Code nur das erste Element zurück.
values[counts.argmax()]
wird der erste Wert zurückgegeben. Um sie alle zu bekommen, können wir verwenden values[counts == counts.max()]
.
>>> # small array
>>> a = [12,3,65,33,12,3,123,888000]
>>>
>>> import collections
>>> collections.Counter(a).most_common()[0][0]
3
>>> %timeit collections.Counter(a).most_common()[0][0]
100000 loops, best of 3: 11.3 µs per loop
>>>
>>> import numpy
>>> numpy.bincount(a).argmax()
3
>>> %timeit numpy.bincount(a).argmax()
100 loops, best of 3: 2.84 ms per loop
>>>
>>> import scipy.stats
>>> scipy.stats.mode(a)[0][0]
3.0
>>> %timeit scipy.stats.mode(a)[0][0]
10000 loops, best of 3: 172 µs per loop
>>>
>>> from collections import defaultdict
>>> def jjc(l):
... d = defaultdict(int)
... for i in a:
... d[i] += 1
... return sorted(d.iteritems(), key=lambda x: x[1], reverse=True)[0]
...
>>> jjc(a)[0]
3
>>> %timeit jjc(a)[0]
100000 loops, best of 3: 5.58 µs per loop
>>>
>>> max(map(lambda val: (a.count(val), val), set(a)))[1]
12
>>> %timeit max(map(lambda val: (a.count(val), val), set(a)))[1]
100000 loops, best of 3: 4.11 µs per loop
>>>
Am besten ist 'max' mit 'set' für kleine Arrays wie das Problem.
Laut @David Sanders ist der Algorithmus "max w / set" bei weitem der schlechteste , wenn Sie die Arraygröße auf etwa 100.000 Elemente erhöhen, während die Methode "numpy bincount" die beste ist.
a = (np.random.rand(100000) * 1000).round().astype('int'); a_list = list(a)
) erhöhen , ist Ihr "max w / set" -Algorithmus bei weitem der schlechteste, während die "numpy bincount" -Methode die beste ist. Ich habe diesen Test mit a_list
nativem Python-Code und a
numpy-Code durchgeführt, um zu vermeiden, dass die Kosten für das Marshalling die Ergebnisse verfälschen.
Auch wenn Sie den häufigsten Wert (positiv oder negativ) erhalten möchten, ohne Module zu laden, können Sie den folgenden Code verwenden:
lVals = [1,2,3,1,2,1,1,1,3,2,2,1]
print max(map(lambda val: (lVals.count(val), val), set(lVals)))
max(set(lVals), key=lVals.count)
, bei dem für jedes eindeutige Element eine O (n) -Zählung von lVals
ungefähr O (n ^ 2) durchgeführt wird (unter der Annahme, dass O (n) eindeutig ist Elemente). Die Verwendung collections.Counter(lVals).most_common(1)[0][0]
aus der Standardbibliothek, wie von JoshAdel vorgeschlagen , ist nur O (n).
Während die meisten der obigen Antworten nützlich sind, falls Sie: 1) nicht positive ganzzahlige Werte (z. B. Gleitkommazahlen oder negative Ganzzahlen ;-)) unterstützen müssen und 2) nicht in Python 2.7 (welche Sammlungen.Counter) enthalten sind erfordert), und 3) ziehen Sie es vor, die Abhängigkeit von scipy (oder sogar numpy) nicht zu Ihrem Code hinzuzufügen, dann ist eine reine Python 2.6-Lösung, die O (nlogn) (dh effizient) ist, genau dies:
from collections import defaultdict
a = [1,2,3,1,2,1,1,1,3,2,2,1]
d = defaultdict(int)
for i in a:
d[i] += 1
most_frequent = sorted(d.iteritems(), key=lambda x: x[1], reverse=True)[0]
Erweitern Sie diese Methode , um den Modus der Daten zu ermitteln, in dem Sie möglicherweise den Index des tatsächlichen Arrays benötigen, um zu sehen, wie weit der Wert vom Zentrum der Verteilung entfernt ist.
(_, idx, counts) = np.unique(a, return_index=True, return_counts=True)
index = idx[np.argmax(counts)]
mode = a[index]
Denken Sie daran, den Modus zu verwerfen, wenn len (np.argmax (Anzahl))> 1 ist
In Python 3 sollte Folgendes funktionieren:
max(set(a), key=lambda x: a.count(x))
Beginnend enthält Python 3.4
die Standardbibliothek die statistics.mode
Funktion, den häufigsten Datenpunkt zurückzugeben.
from statistics import mode
mode([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1])
# 1
Wenn mehrere Modi mit derselben Frequenz vorhanden sind, wird statistics.mode
der erste gefundene zurückgegeben.
Beginnend Python 3.8
gibt die statistics.multimode
Funktion eine Liste der am häufigsten vorkommenden Werte in der Reihenfolge zurück, in der sie zuerst angetroffen wurden:
from statistics import multimode
multimode([1, 2, 3, 1, 2])
# [1, 2]
Hier ist eine allgemeine Lösung, die unabhängig von den Werten mit nur Numpy entlang einer Achse angewendet werden kann. Ich habe auch festgestellt, dass dies viel schneller ist als scipy.stats.mode, wenn es viele eindeutige Werte gibt.
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]
Ich mache vor kurzem ein Projekt und benutze Sammlungen. Counter. (Was mich gefoltert hat).
Der Counter in Sammlungen hat meiner Meinung nach eine sehr sehr schlechte Leistung. Es ist nur ein Klassenumbruch-Diktat ().
Was noch schlimmer ist: Wenn Sie cProfile verwenden, um die Methode zu profilieren, sollten Sie die ganze Zeit über eine Menge '__missing__' und '__instancecheck__' Dinge verschwenden.
Seien Sie vorsichtig, wenn Sie most_common () verwenden, da es jedes Mal eine Sortierung aufruft, die es extrem langsam macht. und wenn Sie most_common (x) verwenden, wird eine Heap-Sortierung aufgerufen, die ebenfalls langsam ist.
Übrigens hat der Bincount von numpy auch ein Problem: Wenn Sie np.bincount ([1,2,4000000]) verwenden, erhalten Sie ein Array mit 4000000 Elementen.
np.bincount([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1]).argmax()