Trovare la modalità di un elenco


126

Dato un elenco di elementi, ricorda che la modalità dell'elenco è l'elemento che ricorre più spesso.

Vorrei sapere come creare una funzione che possa trovare la modalità di una lista ma che visualizzi un messaggio se la lista non ha una modalità (ad esempio, tutti gli elementi della lista compaiono una sola volta). Voglio creare questa funzione senza importare alcuna funzione. Sto cercando di creare la mia funzione da zero.


Non ho capito, ma puoi spiegare cosa intendi esattamente per "modalità della lista"?
Vikas

5
@Vikas: la modalità è l'elemento che ricorre più di frequente (se presente). Alcune definizioni lo estendono per prendere la media aritmetica di tutti questi elementi se ce ne sono più di uno.
Jeremy Roman

Tante risposte sbagliate qui! Ad esempio assert(mode[1, 1, 1]) == Nonee assert(mode[1, 2, 3, 4]) == None. Per un numero sia una mode, deve verificarsi più numero di volte di almeno un altro numero nell'elenco, e deve non essere l'unico numero nell'elenco.
lifebalance

Risposte:


156

Puoi usare la maxfunzione e un tasto. Dai un'occhiata alla funzione Python max usando 'key' e l'espressione lambda .

max(set(lst), key=lst.count)

6
Questa è la risposta corretta a OP, considerando che non richiede alcuna importazione aggiuntiva. Ottimo lavoro, David
Jason Parham

12
Mi sembra che questo funzionerebbe O(n**2). Lo fa?
lirtosiast

7
Questo ha un tempo di esecuzione quadratico
Padraic Cunningham

20
Potrebbe anche solo usare max(lst, key=lst.count). (E davvero non chiamerei un elenco list.)
Stefan Pochmann

2
Qualcuno può spiegare come funziona per le distribuzioni bimodali? es . a = [22, 33, 11, 22, 11]; print(max(set(a), key=a.count))resi 11. Restituirà sempre la modalità minima? E se è così, perché?
battey il

99

Puoi usare quello Counterfornito nella collectionsconfezione che ha una modefunzione -esque

from collections import Counter
data = Counter(your_list_in_here)
data.most_common()   # Returns all unique items and their counts
data.most_common(1)  # Returns the highest occurring item

Nota: Counter è una novità in python 2.7 e non è disponibile nelle versioni precedenti.


19
La domanda afferma che l'utente desidera creare una funzione da zero, ovvero nessuna importazione.
dbliss

3
L'ultima riga restituisce un elenco contenente una tupla contenente una modalità e la sua frequenza. Per ottenere solo una modalità usa Counter(your_list_in_here).most_common(1)[0][0]. Se è presente più di una modalità, ne restituisce una arbitraria.
Rory Daulton

1
Supponiamo che siano npiù comuni modes. Se Counter (your_list_in_here) .most_common (1) [0] [0] ti fa ottenere la prima modalità, come ne otterrai un'altra più comune mode? Basta sostituire l'ultimo 0con 1? Si può creare una funzione per personalizzare modea proprio piacimento ..

1
se c'è più di una modalità, come posso restituire il più grande di questi numeri?
Akin Hwan

59

Python 3.4 include il metodo statistics.mode, quindi è semplice:

>>> from statistics import mode
>>> mode([1, 1, 2, 3, 3, 3, 3, 4])
 3

Puoi avere qualsiasi tipo di elemento nell'elenco, non solo numerico:

>>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
 'red'

17
Genera un errore durante l'utilizzo della modalità ([1, 1,1,1, 2, 3, 3, 3, 3, 4]) dove 1 e 3 ripetono lo stesso numero di volte. Idealmente, dovrebbe restituire il più piccolo del numero che è il numero più grande ma uguale di volte. StatisticsError: nessuna modalità univoca; trovato 2 valori ugualmente comuni
aman_novice

4
Non ho usato questo pacchetto di statistiche 3.4, ma scipy.stats.mode restituirà il più piccolo, in questo caso 1. Tuttavia, preferirei il lancio dell'errore in alcuni casi ...
wordsmith

2
@aman_novice, il problema è stato risolto in Python 3.8. docs.python.org/3/library/statistics.html#statistics.mode
Michael D

2
aggiunto anche python 3.8 multimode, che restituisce più modalità quando ce n'è più di una.
stason

30

Prendendo spunto da alcuni software di statistica, ovvero SciPy e MATLAB , questi restituiscono semplicemente il valore più piccolo più comune, quindi se due valori si verificano allo stesso modo, viene restituito il più piccolo. Si spera che un esempio possa aiutare:

>>> from scipy.stats import mode

>>> mode([1, 2, 3, 4, 5])
(array([ 1.]), array([ 1.]))

>>> mode([1, 2, 2, 3, 3, 4, 5])
(array([ 2.]), array([ 2.]))

>>> mode([1, 2, 2, -3, -3, 4, 5])
(array([-3.]), array([ 2.]))

C'è qualche motivo per cui non puoi seguire questa convenzione?


4
Perché viene restituita solo la modalità più piccola quando ce ne sono più?
zyxue

@zyxue semplice convenzione statistica
chrisfs

2
@chrisfs e per far sì che restituisca la modalità più grande se ce ne sono più?
Akin Hwan

25

Esistono molti modi semplici per trovare la modalità di un elenco in Python come:

import statistics
statistics.mode([1,2,3,3])
>>> 3

Oppure potresti trovare il massimo in base al suo conteggio

max(array, key = array.count)

Il problema con questi due metodi è che non funzionano con più modalità. Il primo restituisce un errore, mentre il secondo restituisce la prima modalità.

Per trovare le modalità di un set, puoi usare questa funzione:

def mode(array):
    most = max(list(map(array.count, array)))
    return list(set(filter(lambda x: array.count(x) == most, array)))

3
Utilizzando la modalità, dà errore quando ci sono due elementi che si verificano nella stessa quantità di tempo.
Abhishek Mishra

Scusa, ho visto questo commento davvero tardi. Statistics.mode (array) restituirebbe un errore con più modalità, ma nessuno degli altri metodi lo fa.
mathwizurd

7

Estendendo la risposta della Comunità che non funzionerà quando l'elenco è vuoto, ecco il codice funzionante per la modalità:

def mode(arr):
        if arr==[]:
            return None
        else:
            return max(set(arr), key=arr.count)

3

Nel caso tu sia interessato alla modalità più piccola, più grande o a tutte:

def get_small_mode(numbers, out_mode):
    counts = {k:numbers.count(k) for k in set(numbers)}
    modes = sorted(dict(filter(lambda x: x[1] == max(counts.values()), counts.items())).keys())
    if out_mode=='smallest':
        return modes[0]
    elif out_mode=='largest':
        return modes[-1]
    else:
        return modes

2

Ho scritto questa pratica funzione per trovare la modalità.

def mode(nums):
    corresponding={}
    occurances=[]
    for i in nums:
            count = nums.count(i)
            corresponding.update({i:count})

    for i in corresponding:
            freq=corresponding[i]
            occurances.append(freq)

    maxFreq=max(occurances)

    keys=corresponding.keys()
    values=corresponding.values()

    index_v = values.index(maxFreq)
    global mode
    mode = keys[index_v]
    return mode

2
Questo metodo fallirà se 2 articoli hanno lo stesso numero. di eventi.
akshaynagpal

2

Breve, ma in qualche modo brutto:

def mode(arr) :
    m = max([arr.count(a) for a in arr])
    return [x for x in arr if arr.count(x) == m][0] if m>1 else None

Usando un dizionario, leggermente meno brutto:

def mode(arr) :
    f = {}
    for a in arr : f[a] = f.get(a,0)+1
    m = max(f.values())
    t = [(x,f[x]) for x in f if f[x]==m]
    return m > 1 t[0][0] else None

2

Un po 'più a lungo, ma può avere più modalità e può ottenere stringhe con la maggior parte dei conteggi o un mix di tipi di dati.

def getmode(inplist):
    '''with list of items as input, returns mode
    '''
    dictofcounts = {}
    listofcounts = []
    for i in inplist:
        countofi = inplist.count(i) # count items for each item in list
        listofcounts.append(countofi) # add counts to list
        dictofcounts[i]=countofi # add counts and item in dict to get later
    maxcount = max(listofcounts) # get max count of items
    if maxcount ==1:
        print "There is no mode for this dataset, values occur only once"
    else:
        modelist = [] # if more than one mode, add to list to print out
        for key, item in dictofcounts.iteritems():
            if item ==maxcount: # get item from original list with most counts
                modelist.append(str(key))
        print "The mode(s) are:",' and '.join(modelist)
        return modelist 

2

Per un numero sia una mode, deve verificarsi più numero di volte di almeno un altro numero nella lista, e deve non essere l'unico numero nell'elenco. Quindi, ho riformattato la risposta di @ mathwizurd (per utilizzare il differencemetodo) come segue:

def mode(array):
    '''
    returns a set containing valid modes
    returns a message if no valid mode exists
      - when all numbers occur the same number of times
      - when only one number occurs in the list 
      - when no number occurs in the list 
    '''
    most = max(map(array.count, array)) if array else None
    mset = set(filter(lambda x: array.count(x) == most, array))
    return mset if set(array) - mset else "list does not have a mode!" 

Questi test vengono superati con successo:

mode([]) == None 
mode([1]) == None
mode([1, 1]) == None 
mode([1, 1, 2, 2]) == None 

1

Perché non solo

def print_mode (thelist):
  counts = {}
  for item in thelist:
    counts [item] = counts.get (item, 0) + 1
  maxcount = 0
  maxitem = None
  for k, v in counts.items ():
    if v > maxcount:
      maxitem = k
      maxcount = v
  if maxcount == 1:
    print "All values only appear once"
  elif counts.values().count (maxcount) > 1:
    print "List has multiple modes"
  else:
    print "Mode of list:", maxitem

Questo non ha alcuni controlli di errore che dovrebbe avere, ma troverà la modalità senza importare alcuna funzione e stamperà un messaggio se tutti i valori appaiono solo una volta. Rileverà anche più elementi che condividono lo stesso conteggio massimo, anche se non era chiaro se lo volevi.


Quindi quello che sto cercando di fare è rilevare più elementi che mostrano lo stesso conteggio e quindi visualizzare tutti gli elementi con lo stesso conteggio
bluelantern

L'hai effettivamente provato tu stesso? L'estensione del mio codice qui per far sì che stampi tutti gli elementi con lo stesso conteggio è abbastanza semplice.
lxop

1

Questa funzione restituisce la modalità o le modalità di una funzione indipendentemente dal numero, nonché la frequenza della modalità o delle modalità nel set di dati. Se non esiste una modalità (cioè tutti gli elementi si verificano solo una volta), la funzione restituisce una stringa di errore. Questo è simile alla funzione di A_nagpal sopra ma è, a mio modesto parere, più completo e penso che sia più facile da capire per qualsiasi principiante di Python (come il tuo veramente) che legga questa domanda per capire.

 def l_mode(list_in):
    count_dict = {}
    for e in (list_in):   
        count = list_in.count(e)
        if e not in count_dict.keys():
            count_dict[e] = count
    max_count = 0 
    for key in count_dict: 
        if count_dict[key] >= max_count:
            max_count = count_dict[key]
    corr_keys = [] 
    for corr_key, count_value in count_dict.items():
        if count_dict[corr_key] == max_count:
            corr_keys.append(corr_key)
    if max_count == 1 and len(count_dict) != 1: 
        return 'There is no mode for this data set. All values occur only once.'
    else: 
        corr_keys = sorted(corr_keys)
        return corr_keys, max_count

Dico questo solo perché hai detto "la funzione restituisce una stringa di errore". La riga che legge return 'There is no mode for this data set. All values occur only once.'può essere trasformata in un messaggio di errore con traceback"condizione if: riga successiva con rientro raise ValueError (" Non esiste una modalità per questo set di dati. Tutti i valori si verificano una sola volta. ") Ecco un elenco di diversi tipi di errori che puoi sollevare.

1

Questo restituirà tutte le modalità:

def mode(numbers)
    largestCount = 0
    modes = []
    for x in numbers:
        if x in modes:
            continue
        count = numbers.count(x)
        if count > largestCount:
            del modes[:]
            modes.append(x)
            largestCount = count
        elif count == largestCount:
            modes.append(x)
    return modes

1

Codice semplice che trova la modalità dell'elenco senza alcuna importazione:

nums = #your_list_goes_here
nums.sort()
counts = dict()
for i in nums:
    counts[i] = counts.get(i, 0) + 1
mode = max(counts, key=counts.get)

In caso di più modalità, dovrebbe restituire il nodo minimo.


0
def mode(inp_list):
    sort_list = sorted(inp_list)
    dict1 = {}
    for i in sort_list:        
            count = sort_list.count(i)
            if i not in dict1.keys():
                dict1[i] = count

    maximum = 0 #no. of occurences
    max_key = -1 #element having the most occurences

    for key in dict1:
        if(dict1[key]>maximum):
            maximum = dict1[key]
            max_key = key 
        elif(dict1[key]==maximum):
            if(key<max_key):
                maximum = dict1[key]
                max_key = key

    return max_key

0
def mode(data):
    lst =[]
    hgh=0
    for i in range(len(data)):
        lst.append(data.count(data[i]))
    m= max(lst)
    ml = [x for x in data if data.count(x)==m ] #to find most frequent values
    mode = []
    for x in ml: #to remove duplicates of mode
        if x not in mode:
        mode.append(x)
    return mode
print mode([1,2,2,2,2,7,7,5,5,5,5])

0

Ecco una semplice funzione che ottiene la prima modalità che compare in un elenco. Crea un dizionario con gli elementi dell'elenco come chiavi e numero di occorrenze, quindi legge i valori di dict per ottenere la modalità.

def findMode(readList):
    numCount={}
    highestNum=0
    for i in readList:
        if i in numCount.keys(): numCount[i] += 1
        else: numCount[i] = 1
    for i in numCount.keys():
        if numCount[i] > highestNum:
            highestNum=numCount[i]
            mode=i
    if highestNum != 1: print(mode)
    elif highestNum == 1: print("All elements of list appear once.")

0

Se vuoi un approccio chiaro, utile per l'aula e utilizzando solo elenchi e dizionari per comprensione, puoi fare:

def mode(my_list):
    # Form a new list with the unique elements
    unique_list = sorted(list(set(my_list)))
    # Create a comprehensive dictionary with the uniques and their count
    appearance = {a:my_list.count(a) for a in unique_list} 
    # Calculate max number of appearances
    max_app = max(appearance.values())
    # Return the elements of the dictionary that appear that # of times
    return {k: v for k, v in appearance.items() if v == max_app}

0
#function to find mode
def mode(data):  
    modecnt=0
#for count of number appearing
    for i in range(len(data)):
        icount=data.count(data[i])
#for storing count of each number in list will be stored
        if icount>modecnt:
#the loop activates if current count if greater than the previous count 
            mode=data[i]
#here the mode of number is stored 
            modecnt=icount
#count of the appearance of number is stored
    return mode
print mode(data1)

Dovresti spiegare la tua risposta con commenti o maggiori dettagli
Michael

0

Ecco come trovare media, mediana e modalità di un elenco:

import numpy as np
from scipy import stats

#to take input
size = int(input())
numbers = list(map(int, input().split()))

print(np.mean(numbers))
print(np.median(numbers))
print(int(stats.mode(numbers)[0]))

0
import numpy as np
def get_mode(xs):
    values, counts = np.unique(xs, return_counts=True)
    max_count_index = np.argmax(counts) #return the index with max value counts
    return values[max_count_index]
print(get_mode([1,7,2,5,3,3,8,3,2]))

0

Per coloro che cercano la modalità minima, ad esempio: caso di distribuzione bimodale, utilizzando numpy.

import numpy as np
mode = np.argmax(np.bincount(your_list))

0

La modalità di un set di dati è / sono i membri che si verificano più frequentemente nel set. Se sono presenti due membri che vengono visualizzati più spesso con lo stesso numero di volte, i dati hanno due modalità. Questo si chiama bimodale .

Se ci sono più di 2 modalità, i dati sarebbero chiamati multimodali . Se tutti i membri nel set di dati vengono visualizzati lo stesso numero di volte, il set di dati non ha alcuna modalità .

La seguente funzione modes()può funzionare per trovare modalità in un dato elenco di dati:

import numpy as np; import pandas as pd

def modes(arr):
    df = pd.DataFrame(arr, columns=['Values'])
    dat = pd.crosstab(df['Values'], columns=['Freq'])
    if len(np.unique((dat['Freq']))) > 1:
        mode = list(dat.index[np.array(dat['Freq'] == max(dat['Freq']))])
        return mode
    else:
        print("There is NO mode in the data set")

Produzione:

# For a list of numbers in x as
In [1]: x = [2, 3, 4, 5, 7, 9, 8, 12, 2, 1, 1, 1, 3, 3, 2, 6, 12, 3, 7, 8, 9, 7, 12, 10, 10, 11, 12, 2]
In [2]: modes(x)
Out[2]: [2, 3, 12]
# For a list of repeated numbers in y as
In [3]: y = [2, 2, 3, 3, 4, 4, 10, 10]
In [4]: modes(y)
There is NO mode in the data set
# For a list of stings/characters in z as
In [5]: z = ['a', 'b', 'b', 'b', 'e', 'e', 'e', 'd', 'g', 'g', 'c', 'g', 'g', 'a', 'a', 'c', 'a']
In [6]: modes(z)
Out[6]: ['a', 'g']

Se non vogliamo importare numpyo pandaschiamare alcuna funzione da questi pacchetti, per ottenere lo stesso output, la modes()funzione può essere scritta come:

def modes(arr):
    cnt = []
    for i in arr:
        cnt.append(arr.count(i))
    uniq_cnt = []
    for i in cnt:
        if i not in uniq_cnt:
            uniq_cnt.append(i)
    if len(uniq_cnt) > 1:
        m = []
        for i in list(range(len(cnt))):
            if cnt[i] == max(uniq_cnt):
                m.append(arr[i])
        mode = []
        for i in m:
            if i not in mode:
                mode.append(i)
        return mode
    else:
        print("There is NO mode in the data set")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.