Предположим, что у меня есть следующий список в python:
a = [1,2,3,1,2,1,1,1,3,2,2,1]
Как найти наиболее частое число в этом списке аккуратным способом?
Предположим, что у меня есть следующий список в python:
a = [1,2,3,1,2,1,1,1,3,2,2,1]
Как найти наиболее частое число в этом списке аккуратным способом?
Если ваш список содержит все неотрицательные ints, вы должны взглянуть на numpy.bincounts:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.bincount.html
а затем, вероятно, используйте np.argmax:
a = np.array([1,2,3,1,2,1,1,1,3,2,2,1])
counts = np.bincount(a)
print np.argmax(counts)
Для более сложного списка (который, возможно, содержит отрицательные числа или нецелые значения), вы можете использовать np.histogram
аналогичным образом. Альтернативно, если вы просто хотите работать на python без использования numpy, collections.Counter
- хороший способ обработки данных такого рода.
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)
Вы можете использовать
(values,counts) = np.unique(a,return_counts=True)
ind=np.argmax(counts)
print values[ind] # prints the most frequent element
Если какой-то элемент является таким же частым, как и другой, этот код вернет только первый элемент.
Если вы хотите использовать SciPy:
>>> from scipy.stats import mode
>>> mode([1,2,3,1,2,1,1,1,3,2,2,1])
(array([ 1.]), array([ 6.]))
>>> most_frequent = mode([1,2,3,1,2,1,1,1,3,2,2,1])[0][0]
>>> most_frequent
1.0
>>> # 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
>>>
Лучше всего 'max' с 'set'
Также, если вы хотите получить наиболее частое значение (положительное или отрицательное) без загрузки каких-либо модулей, вы можете использовать следующий код:
lVals = [1,2,3,1,2,1,1,1,3,2,2,1]
print max(map(lambda val: (lVals.count(val), val), set(lVals)))
Хотя большинство приведенных выше ответов полезны, в случае, если вы: 1) нужно, чтобы он поддерживал значения, не являющиеся положительными целыми числами (например, плавающие или отрицательные целые числа;-)), и 2) не находятся на Python 2.7 (для чего нужны коллекции .Counter), и 3) предпочитают не добавлять зависимостей scipy (или даже numpy) к вашему коду, то чисто чистое решение python 2.6, которое является O (nlogn) (то есть эффективным), является следующим:
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]
Мне нравится решение JoshAdel.
Но есть только один улов.
Решение np.bincount()
работает только с числами.
Если у вас есть строки, решение collections.Counter
будет работать для вас.
Расширение на этот метод, применяемый для поиска режима данных, где вам может понадобиться индекс фактического массива, чтобы увидеть, как далеко это значение от центр распространения.
(_, idx, counts) = np.unique(a, return_index=True, return_counts=True)
index = idx[np.argmax(counts)]
mode = a[index]
Не забывайте отменить режим, когда len (np.argmax(counts)) > 1
Вот общее решение, которое может применяться вдоль оси, независимо от значений, используя чисто numpy. Я также обнаружил, что это намного быстрее, чем scipy.stats.mode, если существует множество уникальных значений.
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]
В Python 3 должно работать следующее:
max(set(li), key=lambda x: li.count(x))
Недавно я делал проект и использовал коллекции. Каунтер. (Который мучил меня).
Счетчик в коллекциях имеет очень плохую производительность, на мой взгляд. Это просто класс wrapping dict().
Чем хуже, если вы используете cProfile для профайла его метода, вы должны увидеть много вещей __missing__ и '__instancecheck__', которые все время тратятся впустую.
Будьте осторожны, используя его most_common(), потому что каждый раз он вызывает тип, который делает его чрезвычайно медленным. и если вы используете most_common (x), он будет вызывать сортировку кучи, которая также замедляется.
Btw, numpy bincount также имеет проблему: если вы используете np.bincount([1,2,4000000]), вы получите массив с 4000000 элементами.