Encontrar el modo de una lista

126

Dada una lista de elementos, recuerde que el modo de la lista es el elemento que ocurre con mayor frecuencia.

Me gustaría saber cómo crear una función que pueda encontrar el modo de una lista pero que muestre un mensaje si la lista no tiene un modo (por ejemplo, todos los elementos de la lista solo aparecen una vez). Quiero hacer esta función sin importar ninguna función. Estoy tratando de hacer mi propia función desde cero.

Bluelantern
fuente
Lo siento, pero ¿puedes explicar qué quieres decir exactamente con 'modo de la lista'?
Vikas
55
@Vikas: el modo es el elemento más frecuente (si lo hay). Algunas definiciones lo extienden para tomar la media aritmética de todos esos elementos si hay más de uno.
Jeremy Roman
¡Tantas respuestas incorrectas aquí! Para por ejemplo, assert(mode[1, 1, 1]) == Noney assert(mode[1, 2, 3, 4]) == None. Para un número que sea una mode, debe facilitarse a un mayor número de veces de las que al menos otro número en la lista, y debe no ser el único número en la lista.
Lifebalance

Respuestas:

156

Puede usar la maxfunción y una tecla. Eche un vistazo a la función python max usando 'key' y la expresión lambda .

max(set(lst), key=lst.count)
David Dao
fuente
66
Esta es la respuesta correcta a OP, considerando que no requiere ninguna importación adicional. Buen trabajo, David
Jason Parham
12
Me parece que esto correría O(n**2). ¿Lo hace?
lirtosiast
77
Esto tiene un tiempo de ejecución cuadrático
Padraic Cunningham
20
También podría simplemente usar max(lst, key=lst.count). (Y realmente no llamaría a una lista list.)
Stefan Pochmann
2
¿Alguien puede explicar cómo funciona esto para las distribuciones bimodales? Por ejemplo, a = [22, 33, 11, 22, 11]; print(max(set(a), key=a.count))devoluciones 11. ¿Siempre devolverá el modo mínimo? Y si es así, ¿por qué?
Battey
99

Puede usar el Countersuministrado en el collectionspaquete que tiene una modefunción -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 es nuevo en python 2.7 y no está disponible en versiones anteriores.

Christian Witts
fuente
19
La pregunta establece que el usuario desea realizar una función desde cero, es decir, no importar.
dbliss
3
Su última línea devuelve una lista que contiene una tupla que contiene un modo y su frecuencia. Para obtener solo un modo de uso Counter(your_list_in_here).most_common(1)[0][0]. Si hay más de un modo, esto devuelve uno arbitrario.
Rory Daulton
1
Supongamos que hay nmás comunes modes. Si Counter (your_list_in_here) .most_common (1) [0] [0] te da el primer modo, ¿cómo obtendrías otro más común mode? Solo reemplaza el último 0con 1? Uno puede hacer una función para personalizarlo modea su gusto ..
1
Si hay más de un modo, ¿cómo puedo devolver el mayor de estos números?
Akin Hwan
59

Python 3.4 incluye el método statistics.mode, por lo que es sencillo:

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

Puede tener cualquier tipo de elementos en la lista, no solo numéricos:

>>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
 'red'
jabaldonedo
fuente
17
Lanza un error al usar el modo ([1, 1,1,1, 2, 3, 3, 3, 3, 4]) donde 1 y 3 repiten el mismo número de veces. Idealmente, debería devolver el número más pequeño del número más grande pero igual de veces. StatisticsError: sin modo único; encontró 2 valores igualmente comunes
aman_novice 01 de
44
No han utilizado este paquete 3.4 estadísticas, pero scipy.stats.mode volverá el más pequeño, en este caso 1. Me gustaría, sin embargo, prefieren de banda del error en ciertos casos ...
artesano de la palabra
2
@aman_novice, el problema se resolvió en Python 3.8. docs.python.org/3/library/statistics.html#statistics.mode
Michael D
2
También se agregó Python 3.8 multimode, que devuelve múltiples modos cuando hay más de uno.
stason
30

Tomando una hoja de algunos software de estadísticas, a saber, SciPy y MATLAB , estos solo devuelven el valor más pequeño más común, por lo que si dos valores ocurren con la misma frecuencia, se devuelve el más pequeño. Esperemos que un ejemplo ayude:

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

¿Hay alguna razón por la cual no puedes seguir esta convención?

Chris
fuente
44
¿Por qué solo se devuelve el modo más pequeño cuando hay múltiples?
zyxue
@zyxue convención estadística simple
chrisfs
2
@chrisfs y para que devuelva el modo más grande si hay múltiples?
Akin Hwan
25

Hay muchas formas simples de encontrar el modo de una lista en Python como:

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

O bien, puede encontrar el máximo por su recuento

max(array, key = array.count)

El problema con esos dos métodos es que no funcionan con múltiples modos. El primero devuelve un error, mientras que el segundo devuelve el primer modo.

Para encontrar los modos de un conjunto, puede usar esta función:

def mode(array):
    most = max(list(map(array.count, array)))
    return list(set(filter(lambda x: array.count(x) == most, array)))
Mathwizurd
fuente
3
Usando el modo, da error cuando hay dos elementos que ocurren la misma cantidad de tiempo.
Abhishek Mishra
Lo siento, vi este comentario muy tarde. Statistics.mode (array) devolvería un error con múltiples modos, pero ninguno de los otros métodos lo hace.
Mathwizurd
7

Extendiendo la respuesta de la Comunidad que no funcionará cuando la lista esté vacía, aquí está el código de modo:

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

En caso de que esté interesado en los modos más pequeño, más grande o todos:

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
tashuhka
fuente
2

Escribí esta práctica función para encontrar el modo.

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
usuario2975335
fuente
2
Este método fallará si 2 elementos tienen el mismo no. de ocurrencias.
akshaynagpal
2

Corto, pero de alguna manera feo:

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 diccionario, un poco menos feo:

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
Carl
fuente
2

Un poco más, pero puede tener múltiples modos y puede obtener cadenas con la mayoría de los recuentos o una combinación de tipos de datos.

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 
timpjohns
fuente
2

Para un número que sea una mode, debe facilitarse a un mayor número de veces de las que al menos otro número en la lista, y debe no ser el único número en la lista. Entonces, refactoré la respuesta de @ mathwizurd (para usar el differencemétodo) de la siguiente manera:

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!" 

Estas pruebas pasan con éxito:

mode([]) == None 
mode([1]) == None
mode([1, 1]) == None 
mode([1, 1, 2, 2]) == None 
Balance de vida
fuente
1

¿Por qué no 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

Esto no tiene algunas verificaciones de error que debería tener, pero encontrará el modo sin importar ninguna función e imprimirá un mensaje si todos los valores aparecen solo una vez. También detectará varios elementos que comparten el mismo recuento máximo, aunque no estaba claro si quería eso.

lxop
fuente
Entonces, lo que estoy tratando de hacer es detectar varios elementos que muestran el mismo recuento y luego mostrar todos los elementos con ese mismo recuento
bluelantern
¿Realmente has intentado esto tú mismo? La extensión de mi código aquí para que imprima todos los elementos con el mismo recuento es bastante sencilla.
lxop
1

Esta función devuelve el modo o modos de una función sin importar cuántos, así como la frecuencia del modo o modos en el conjunto de datos. Si no hay modo (es decir, todos los elementos se producen solo una vez), la función devuelve una cadena de error. Esto es similar a la función anterior de A_nagpal pero, en mi humilde opinión, es más completa, y creo que es más fácil de entender para cualquier principiante de Python (como el suyo) que lea esta pregunta para entender.

 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
usuario4406935
fuente
Digo esto solo porque dijiste "la función devuelve una cadena de error". La línea que se lee return 'There is no mode for this data set. All values occur only once.'puede convertirse en un mensaje de error con la tracebackcondición `if: la siguiente línea con sangría aumenta ValueError ('No hay modo para este conjunto de datos. Todos los valores ocurren solo una vez'). Aquí hay una lista de diferentes tipos de Errores que puede plantear.
1

Esto devolverá todos los modos:

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
Tim Orton
fuente
1

Código simple que encuentra el modo de la lista sin ninguna importación:

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)

En caso de modos múltiples, debería devolver el nodo mínimo.

baby_yoda
fuente
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
akshaynagpal
fuente
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])
Venkata Prasanth T
fuente
0

Aquí hay una función simple que obtiene el primer modo que ocurre en una lista. Crea un diccionario con los elementos de la lista como claves y número de ocurrencias y luego lee los valores dict para obtener el modo.

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.")
SMS von der Tann
fuente
0

Si desea un enfoque claro, útil para el aula y que solo utiliza listas y diccionarios por comprensión, puede hacer lo siguiente:

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}
María Frances Gaska
fuente
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)

fuente
Debería explicar su respuesta con comentarios o más detalles
Michael
0

Así es como puedes encontrar la media, la mediana y la moda de una lista:

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]))
pankaj
fuente
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]))
sim
fuente
0

Para aquellos que buscan el modo mínimo, por ejemplo: caso de distribución bimodal, usando numpy.

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

El modo de un conjunto de datos es el / los miembro (s) que ocurren (s) con más frecuencia en el conjunto. Si hay dos miembros que aparecen con mayor frecuencia con el mismo número de veces, entonces los datos tienen dos modos. Se llama bimodal .

Si hay más de 2 modos, los datos se denominarán multimodales . Si todos los miembros del conjunto de datos aparecen la misma cantidad de veces, entonces el conjunto de datos no tiene modo alguno.

La siguiente función modes()puede funcionar para encontrar modos en una lista de datos dada:

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")

Salida:

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

Si no queremos importar numpyo pandasllamar a ninguna función de estos paquetes, para obtener esta misma salida, la modes()función se puede escribir como:

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")
shubh
fuente