Python'da aşağıdaki listeye sahip olduğumu varsayalım:
a = [1,2,3,1,2,1,1,1,3,2,2,1]
Bu listedeki en sık sayıları düzgün bir şekilde nasıl bulabilirim?
Python'da aşağıdaki listeye sahip olduğumu varsayalım:
a = [1,2,3,1,2,1,1,1,3,2,2,1]
Bu listedeki en sık sayıları düzgün bir şekilde nasıl bulabilirim?
Yanıtlar:
Listeniz tüm negatif olmayan girişleri içeriyorsa, numpy.bincounts'a bir göz atmalısınız:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.bincount.html
ve sonra muhtemelen np.argmax kullanın:
a = np.array([1,2,3,1,2,1,1,1,3,2,2,1])
counts = np.bincount(a)
print(np.argmax(counts))
Daha karmaşık bir liste için (negatif sayılar veya tam sayı olmayan değerler içeren) np.histogram
benzer bir şekilde kullanabilirsiniz. Alternatif olarak, numpy kullanmadan sadece python'da çalışmak istiyorsanız, collections.Counter
bu tür verileri işlemenin iyi bir yoludur.
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
az genel olmasına rağmen , en azından daha büyük bir mertebedir .
Counter(array).most_common(1)[0][0]
Kullanabilirsin
(values,counts) = np.unique(a,return_counts=True)
ind=np.argmax(counts)
print values[ind] # prints the most frequent element
Bazı elemanlar bir başkası kadar sıksa, bu kod sadece ilk elemanı döndürecektir.
values[counts.argmax()]
ilk değeri döndürür. Hepsini almak için kullanabiliriz 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
>>>
En iyisi, problem gibi küçük diziler için 'set' ile 'max' dir .
@David Sanders'a göre, dizi boyutunu 100.000 öğe gibi bir şeye yükseltirseniz, "maks w / set" algoritması en kötüsü olurken "numpy bincount" yöntemi en iyisidir.
a = (np.random.rand(100000) * 1000).round().astype('int'); a_list = list(a)
) değerine yükseltirseniz, "maks. / Set" algoritmanız en kötüsü olurken "numpy bincount" yöntemi en iyisidir. Bu testi a_list
yerel python kodunu kullanarak ve a
sıralama maliyetlerinin sonuçları altüst etmesini önlemek için numpy kodu kullanarak yaptım .
Ayrıca, herhangi bir modül yüklemeden en sık değeri (pozitif veya negatif) almak istiyorsanız, aşağıdaki kodu kullanabilirsiniz:
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)
her benzersiz öğe lVals
için yaklaşık O (n ^ 2) için bir O (n) sayar (O (n) benzersiz olduğu varsayılırsa) elementler). JoshAdel'in önerdiğicollections.Counter(lVals).most_common(1)[0][0]
gibi standart kitaplıktan kullanmak sadece O (n) 'dir.
Yukarıdaki cevapların çoğu yararlı olsa da: 1) pozitif olmayan tamsayı değerleri (örneğin, kayan sayılar veya negatif tamsayılar ;-)) desteklemesi gerekiyorsa ve 2) Python 2.7'de (hangi koleksiyonlar. gerektirir) ve 3) kodunuza scipy bağımlılığını (veya hatta numpy) eklememeyi tercih ederseniz, O (nlogn) (yani verimli) olan tamamen bir python 2.6 çözümü tam olarak şudur:
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]
Bu yöntemin genişletilmesi , değerin dağılımın merkezinden ne kadar uzakta olduğunu görmek için gerçek dizinin dizinine ihtiyaç duyabileceğiniz veri modunu bulmaya uygulanır.
(_, idx, counts) = np.unique(a, return_index=True, return_counts=True)
index = idx[np.argmax(counts)]
mode = a[index]
Len (np.argmax (sayım))> 1 olduğunda modu atmayı unutmayın
Python 3'te aşağıdakiler çalışmalıdır:
max(set(a), key=lambda x: a.count(x))
Başlangıç olarak Python 3.4
, standart kitaplık statistics.mode
en yaygın tek veri noktasını döndürme işlevini içerir .
from statistics import mode
mode([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1])
# 1
Aynı frekansa sahip birden fazla mod varsa statistics.mode
karşılaşılan ilkini döndürür.
Başlarken Python 3.8
, statistics.multimode
işlev en sık karşılaşılan değerlerin bir listesini ilk karşılaştıkları sırayla döndürür:
from statistics import multimode
multimode([1, 2, 3, 1, 2])
# [1, 2]
İşte, değerlerden bağımsız olarak, tamamen numpy kullanılarak bir eksen boyunca uygulanabilecek genel bir çözüm. Ayrıca, çok sayıda benzersiz değer varsa, bunun scipy.stats.mode'dan çok daha hızlı olduğunu buldum.
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]
Son zamanlarda bir proje yapıyorum ve collections.Counter kullanıyorum. (Bana işkence eden).
Koleksiyonlardaki sayaç bence çok kötü bir performans sergiliyor. Bu sadece bir sınıf kaplama diktesi ().
Daha da kötüsü, yönteminin profilini çıkarmak için cProfile kullanırsanız, tüm zamanınızı boşa harcayan birçok "__missing__" ve "__instancecheck__" görmelisiniz.
Most_common () işlevini kullanırken dikkatli olun, çünkü her seferinde onu aşırı derecede yavaşlatan bir sıralama çağırır. ve most_common (x) kullanırsanız, aynı zamanda yavaş olan bir yığın sıralaması başlatacaktır.
Btw, numpy'nin bincount'unda da bir sorun var: np.bincount ([1,2,4000000]) kullanırsanız, 4000000 elemanlı bir dizi elde edersiniz.
np.bincount([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1]).argmax()