88

Giả sử tôi có danh sách sau trong python:

a = [1,2,3,1,2,1,1,1,3,2,2,1]

Làm thế nào để tìm số thường xuyên nhất trong danh sách này một cách gọn gàng?

|
158

Nếu danh sách của bạn chứa tất cả các số nguyên không âm, bạn nên xem numpy.bincounts:

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

và sau đó có thể sử dụng 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)

Đối với một danh sách phức tạp hơn (có lẽ chứa các số âm hoặc giá trị không nguyên), bạn có thể sử dụng np.histogramtheo cách tương tự. Ngoài ra, nếu bạn chỉ muốn làm việc trong python mà không sử dụng numpy, collections.Counterlà một cách tốt để xử lý loại dữ liệu này.

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)
|
  • 1

    +1. Có thể chỉ lànp.bincount([1, 2, 3, 1, 2, 1, 1, 1, 3, 2, 2, 1]).argmax()

    – Hoàng Lam Tuyền 13:09:20 06/06/2011
  • 1

    +1. Đây ít nhất là một thứ tự cường độ nhanh hơn scipy.stats.mode, mặc dù ít chung hơn.

    – Ngô Yến My 13:14:54 06/06/2011
  • 1

    Tôi muốn cho bạn thêm +1; Tôi không biết về chức năng này, nhưng chỉ cần sử dụng tốt vào chiều nay!

    – Lý Tường Chinh 17:55:03 06/06/2011
  • 1

    Câu trả lời tốt đẹp! Tuy nhiên, nếu ai đó đang dùng python 2.6, bộ sưu tập. Bộ đếm không khả dụng. Trong trường hợp đó, xem câu trả lời của tôi dưới đây.

    – Bùi Trọng Kiên 17:00:14 01/07/2013
  • 1

    Đối với những người trong chúng ta truy cập sau năm 2016: Tôi không thích câu trả lời này, vì bincount (mảng) trả về một mảng lớn bằng phần tử lớn nhất trong mảng, do đó, một mảng nhỏ với phạm vi lớn sẽ tạo ra một mảng quá lớn. Câu trả lời của Apoengtus dưới đây tốt hơn nhiều, mặc dù tôi không nghĩ numpy.unique () tồn tại vào năm 2011, khi câu trả lời này được tạo ra.

    – Dương Đức Hoàng 22:03:52 13/03/2016
60

Bạn có thể sử dụng

(values,counts) = np.unique(a,return_counts=True)
ind=np.argmax(counts)
print values[ind]  # prints the most frequent element

Nếu một số phần tử thường xuyên như một phần tử khác, mã này sẽ chỉ trả về phần tử đầu tiên.

|
  • 1

    Tôi thấy điều này hữu ích nhất vì nó chung chung, ngắn gọn và cho phép kéo các yếu tố từ các giá trị hoặc đếm bằng một số chỉ số dẫn xuất.

    – Hoàng Lam Tuyền 13:16:16 22/09/2015
  • 1

    Nếu chúng ta có nhiều giá trị thường xuyên nhất, values[counts.argmax()]sẽ trả về giá trị đầu tiên. Để có được tất cả chúng, chúng ta có thể sử dụng values[counts == counts.max()].

    – Ngô Yến My 03:43:31 23/01/2019
32

Nếu bạn sẵn sàng sử dụng 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
|
22

Biểu diễn (sử dụng iPython) cho một số giải pháp được tìm thấy ở đây:

>>> # 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
>>> 

Tốt nhất là 'tối đa' với 'thiết lập'

|
  • 1

    collections.Countercó vẻ như là một sự đánh đổi tốt

    – Hoàng Lam Tuyền 17:16:05 23/03/2016
  • 1

    @IuliusCurt để chỉ ra cách tiếp cận tốt nhất, chúng tôi cần thử nghiệm nó với nhiều trường hợp: mảng nhỏ, mảng lớn, mảng ngẫu nhiên, mảng thế giới thực (như timsort làm để sắp xếp), ... Nhưng tôi đồng ý với bạn

    – Ngô Yến My 13:12:29 27/03/2016
  • 1

    Chỉ sử dụng một mảng nhỏ, như trong cách tiếp cận của bạn, sẽ không phân biệt rất rõ giữa các thuật toán khác nhau.

    – Lý Tường Chinh 21:53:22 10/12/2016
  • 1

    Nếu bạn tăng kích thước danh sách kiểm tra lên 100000 ( a = (np.random.rand(100000) * 1000).round().astype('int'); a_list = list(a)), thuật toán "max w / set" của bạn sẽ trở thành tồi tệ nhất trong khi phương pháp "numpy bincount" là tốt nhất. Tôi đã tiến hành thử nghiệm này bằng cách sử dụng a_listmã python bản địa và amã numpy để tránh chi phí sắp xếp sai lệch làm hỏng kết quả.

    – Bùi Trọng Kiên 22:16:24 10/12/2016
2

Mặc dù hầu hết các câu trả lời ở trên đều hữu ích, nhưng trong trường hợp bạn: 1) cần nó để hỗ trợ các giá trị nguyên không dương (ví dụ: float hoặc số nguyên âm ;-)) và 2) không có trên Python 2.7 (bộ sưu tập. yêu cầu) và 3) không muốn thêm sự phụ thuộc của scipy (hoặc thậm chí là numpy) vào mã của bạn, sau đó một giải pháp hoàn toàn python 2.6 là O (nlogn) (nghĩa là hiệu quả) chỉ là:

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]
|
2

Ngoài ra nếu bạn muốn nhận giá trị thường xuyên nhất (tích cực hoặc tiêu cực) mà không cần tải bất kỳ mô-đun nào, bạn có thể sử dụng mã sau đây:

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

    Cách đây một thời gian, nhưng đối với hậu thế: điều này tương đương với việc dễ đọc hơn max(set(lVals), key=lVals.count), tính O (n) cho mỗi phần tử duy nhất của lValskhoảng O (n ^ 2) (giả sử O (n) duy nhất các yếu tố). Sử dụng collections.Counter(lVals).most_common(1)[0][0]từ thư viện chuẩn, như được đề xuất bởi JoshAdel , chỉ là O (n).

    – Trịnh Vân Quyên 16:46:50 14/08/2012
1

Gần đây tôi đang thực hiện một dự án và sử dụng các bộ sưu tập. Cuộc gặp gỡ (đã hành hạ tôi).

Theo tôi, Counter trong các bộ sưu tập có hiệu suất rất rất tệ. Nó chỉ là một lớp bọc dict ().

Tệ hơn nữa, nếu bạn sử dụng cProfile để lập hồ sơ phương thức của nó, bạn sẽ thấy rất nhiều thứ '__missing__' và '__instancecheck__' lãng phí toàn bộ thời gian.

Hãy cẩn thận khi sử dụng most_common () của nó, bởi vì mỗi lần nó sẽ gọi một loại khiến nó cực kỳ chậm. và nếu bạn sử dụng most_common (x), nó sẽ gọi một loại heap, cũng chậm.

Btw, bincount của numpy cũng có một vấn đề: nếu bạn sử dụng np.bincount ([1,2,4000000]), bạn sẽ nhận được một mảng với 4000000 phần tử.

|
  • 1

    Một dict là cấu trúc dữ liệu được điều chỉnh tốt nhất trong Python và lý tưởng để đếm các đối tượng tùy ý. Ngược lại, binning chỉ hoạt động trên các giá trị số và không cho phép bạn ngăn răng cưa giữa các giá trị rời rạc cách nhau. Trong trường hợp của Counter, phương thức __missing__ chỉ được gọi khi một phần tử được nhìn thấy lần đầu tiên; mặt khác, sự hiện diện của nó là miễn phí. Lưu ý, phương thức most_common () rất nhanh trong hầu hết các trường hợp vì heap rất nhỏ so với tổng số liệu. Trong hầu hết các trường hợp, phương thức most_common () chỉ thực hiện so sánh nhiều hơn một chút so với min () .

    – Trịnh Vân Quyên 21:46:20 31/03/2013
1

Mở rộng trên phương thức này , được áp dụng để tìm chế độ của dữ liệu mà bạn có thể cần chỉ mục của mảng thực tế để xem giá trị cách trung tâm phân phối bao xa.

(_, idx, counts) = np.unique(a, return_index=True, return_counts=True)
index = idx[np.argmax(counts)]
mode = a[index]

Nhớ loại bỏ chế độ khi len (np.argmax (đếm))> 1

|
1

Tôi thích giải pháp của JoshAdel.

Nhưng chỉ có một nắm bắt.

Các np.bincount()giải pháp chỉ hoạt động trên số.

Nếu bạn có chuỗi, collections.Countergiải pháp sẽ làm việc cho bạn.

|
0

Đây là một giải pháp chung có thể được áp dụng dọc theo một trục, bất kể giá trị, sử dụng hoàn toàn numpy. Tôi cũng thấy rằng điều này nhanh hơn nhiều so với scipy.stats.mode nếu có nhiều giá trị duy nhất.

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]
|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.