Misalkan saya memiliki daftar berikut di python:
a = [1,2,3,1,2,1,1,1,3,2,2,1]
Bagaimana menemukan nomor paling sering dalam daftar ini dengan cara yang rapi?
Misalkan saya memiliki daftar berikut di python:
a = [1,2,3,1,2,1,1,1,3,2,2,1]
Bagaimana menemukan nomor paling sering dalam daftar ini dengan cara yang rapi?
Jawaban:
Jika daftar Anda berisi semua int non-negatif, Anda harus melihat di numpy.bincounts:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.bincount.html
dan mungkin menggunakan 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))
Untuk daftar yang lebih rumit (yang mungkin berisi angka negatif atau nilai non-integer), Anda dapat menggunakan np.histogram
dengan cara yang serupa. Alternatifnya, jika Anda hanya ingin bekerja dengan python tanpa menggunakan numpy, collections.Counter
adalah cara yang baik untuk menangani data semacam ini.
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
, meskipun kurang umum.
Counter(array).most_common(1)[0][0]
Anda dapat menggunakan
(values,counts) = np.unique(a,return_counts=True)
ind=np.argmax(counts)
print values[ind] # prints the most frequent element
Jika beberapa elemen sama seringnya dengan yang lain, kode ini hanya akan mengembalikan elemen pertama.
values[counts.argmax()]
akan mengembalikan nilai pertama. Untuk mendapatkan semuanya, kita bisa menggunakan 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
>>>
Yang terbaik adalah 'max' dengan 'set' untuk array kecil seperti masalahnya.
Menurut @David Sanders, jika Anda meningkatkan ukuran array hingga 100.000 elemen, algoritme "max w / set" akan menjadi yang terburuk sejauh ini sedangkan metode "numpy bincount" adalah yang terbaik.
a = (np.random.rand(100000) * 1000).round().astype('int'); a_list = list(a)
), algoritme "max w / set" Anda akan menjadi yang terburuk sejauh ini sedangkan metode "numpy bincount" adalah yang terbaik. Saya melakukan tes ini menggunakan a_list
kode python asli dan a
untuk kode numpy untuk menghindari biaya penyusunan yang mengacaukan hasil.
Juga jika Anda ingin mendapatkan nilai paling sering (positif atau negatif) tanpa memuat modul apa pun, Anda dapat menggunakan kode berikut:
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)
, yang menghitung O (n) untuk setiap elemen unik lVals
untuk sekitar O (n ^ 2) (dengan asumsi O (n) unik elemen). Menggunakan collections.Counter(lVals).most_common(1)[0][0]
dari pustaka standar, seperti yang disarankan oleh JoshAdel , hanya O (n).
Meskipun sebagian besar jawaban di atas berguna, jika Anda: 1) membutuhkannya untuk mendukung nilai non-positif-integer (misalnya float atau integer negatif ;-)), dan 2) tidak ada di Python 2.7 (yang koleksi. memerlukan), dan 3) memilih untuk tidak menambahkan ketergantungan scipy (atau bahkan numpy) ke kode Anda, maka solusi murni python 2.6 yaitu O (nlogn) (yaitu, efisien) hanya ini:
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]
Memperluas metode ini , diterapkan untuk menemukan mode data di mana Anda mungkin memerlukan indeks array sebenarnya untuk melihat seberapa jauh nilai tersebut dari pusat distribusi.
(_, idx, counts) = np.unique(a, return_index=True, return_counts=True)
index = idx[np.argmax(counts)]
mode = a[index]
Ingatlah untuk membuang mode ketika len (np.argmax (hitungan))> 1
Di Python 3, berikut ini seharusnya berfungsi:
max(set(a), key=lambda x: a.count(x))
Dimulai Python 3.4
, pustaka standar menyertakan statistics.mode
fungsi untuk mengembalikan satu titik data paling umum.
from statistics import mode
mode([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1])
# 1
Jika ada beberapa mode dengan frekuensi yang sama, statistics.mode
mengembalikan mode yang pertama kali ditemukan.
Dimulai Python 3.8
, statistics.multimode
fungsi mengembalikan daftar nilai yang paling sering muncul dalam urutan saat pertama kali ditemukan:
from statistics import multimode
multimode([1, 2, 3, 1, 2])
# [1, 2]
Berikut adalah solusi umum yang dapat diterapkan di sepanjang sumbu, berapa pun nilainya, menggunakan numpy murni. Saya juga menemukan bahwa ini jauh lebih cepat daripada scipy.stats.mode jika ada banyak nilai unik.
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]
Saya baru-baru ini melakukan proyek dan menggunakan collections.Counter (Yang menyiksa saya).
Counter dalam koleksi memiliki performa yang sangat sangat buruk menurut saya. Ini hanya diktik pembungkus kelas ().
Yang lebih buruk, Jika Anda menggunakan cProfile untuk membuat profil metodenya, Anda akan melihat banyak hal '__missing__' dan '__instancecheck__' yang terbuang percuma.
Hati-hati menggunakan most_common (), karena setiap kali itu akan memanggil semacam yang membuatnya sangat lambat. dan jika Anda menggunakan most_common (x), ini akan memanggil jenis heap, yang juga lambat.
Btw, numpy bincount juga bermasalah: jika Anda menggunakan np.bincount ([1,2,4000000]), Anda akan mendapatkan array dengan 4000000 elemen.
np.bincount([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1]).argmax()