Localizando o modo de uma lista

126

Dada uma lista de itens, lembre-se de que o modo da lista é o item que ocorre com mais frequência.

Gostaria de saber como criar uma função que pode encontrar o modo de uma lista, mas que exibe uma mensagem se a lista não tiver um modo (por exemplo, todos os itens da lista aparecem apenas uma vez). Eu quero fazer essa função sem importar nenhuma função. Estou tentando fazer minha própria função do zero.

bluelantern
fonte
Desculpe, mas você pode explicar exatamente o que você quer dizer com 'modo da lista'?
Vikas
5
@ Vikas: o modo é o elemento que ocorre com mais frequência (se houver). Algumas definições o estendem para obter a média aritmética de todos esses elementos, se houver mais de um.
Jeremy Roman
Tantas respostas erradas aqui! Por exemplo, assert(mode[1, 1, 1]) == Nonee assert(mode[1, 2, 3, 4]) == None. Para um número para ser um mode, deve ocorrer com mais número de vezes que pelo menos um outro número na lista, e deve não ser o único número na lista.
lifebalance

Respostas:

156

Você pode usar a maxfunção e uma tecla. Veja a função python max usando a expressão 'key' e lambda .

max(set(lst), key=lst.count)
David Dao
fonte
6
Esta é a resposta correta para o OP, considerando que ele não requer nenhuma importação extra. Bom trabalho, David
Jason Parham
12
Parece-me que isso ocorreria O(n**2). Faz isso?
lirtosiast
7
Isto tem tempo de execução quadrática
Padraic Cunningham
20
Também poderia apenas usar max(lst, key=lst.count). (E eu realmente não chamaria de uma lista list.)
Stefan Pochmann
2
Alguém pode explicar como isso funciona para distribuições bi-modais? por exemplo, a = [22, 33, 11, 22, 11]; print(max(set(a), key=a.count))retornos 11. Ele sempre retornará o modo mínimo? E se sim, por quê?
battey
99

Você pode usar o Counterfornecido na collectionsembalagem que possui uma modefunção -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: O contador é novo no python 2.7 e não está disponível nas versões anteriores.

Christian Witts
fonte
19
A pergunta afirma que o usuário deseja fazer uma função do zero - ou seja, sem importações.
dbliss
3
Sua última linha retorna uma lista contendo uma tupla contendo um modo e sua frequência. Para obter apenas um modo, use Counter(your_list_in_here).most_common(1)[0][0]. Se houver mais de um modo, isso retornará um modo arbitrário.
Rory Daulton
1
Suponha que sejam os nmais comuns modes. Se Counter (your_list_in_here) .most_common (1) [0] [0] obtém o primeiro modo, como você conseguiria outro mais comum mode? Basta substituir o último 0por 1? Pode-se fazer uma função para personalizar o modeao seu gosto ..
1
se houver mais de um modo, como posso retornar o maior desses números?
Akin Hwan
59

O Python 3.4 inclui o método statistics.mode, por isso é direto:

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

Você pode ter qualquer tipo de elemento na lista, não apenas numérico:

>>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
 'red'
jabaldonedo
fonte
17
Lança erro ao usar o modo ([1, 1,1,1, 2, 3, 3, 3, 3, 4]), onde 1 e 3 repetem o mesmo número de vezes. Idealmente, deve retornar o menor número que maior, mas igual número de vezes. StatisticsError: nenhum modo exclusivo; encontrada 2 valores igualmente comuns
aman_novice
4
Não usei este pacote de estatísticas 3.4, mas o scipy.stats.mode retornará o menor, neste caso 1. No entanto, eu preferiria o lançamento do erro em certos casos ...
wordsmith
2
@aman_novice, o problema foi resolvido no Python 3.8. docs.python.org/3/library/statistics.html#statistics.mode
Michael D
2
Também foi adicionado o python 3.8 multimode, que retorna vários modos quando há mais de um.
stason 12/03
30

Tomando uma folha de alguns softwares de estatística, como SciPy e MATLAB , eles retornam o menor valor mais comum; portanto, se dois valores ocorrem com a mesma frequência, o menor deles é retornado. Espero que um exemplo ajude:

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

Existe alguma razão para você não seguir esta convenção?

Chris
fonte
4
Por que apenas o modo menor é retornado quando há vários?
zyxue
@zyxue convenção estatística simples
chrisfs
2
@chrisfs e fazê-lo retornar o modo maior, se houver vários?
Akin Hwan
25

Existem muitas maneiras simples de encontrar o modo de uma lista no Python, como:

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

Ou você pode encontrar o máximo pela contagem

max(array, key = array.count)

O problema com esses dois métodos é que eles não funcionam com vários modos. O primeiro retorna um erro, enquanto o segundo retorna o primeiro modo.

Para encontrar os modos de um conjunto, você pode usar esta função:

def mode(array):
    most = max(list(map(array.count, array)))
    return list(set(filter(lambda x: array.count(x) == most, array)))
mathwizurd
fonte
3
Usando o modo, ocorre erro quando há dois elementos que ocorrem na mesma quantidade de tempo.
Abhishek Mishra
Desculpe, vi este comentário muito tarde. O Statistics.mode (array) retornaria um erro com vários modos, mas nenhum dos outros métodos retornaria.
Mathwizurd 9/05/19
7

Estendendo a resposta da Comunidade que não funcionará quando a lista estiver vazia, aqui está o código de funcionamento para o modo:

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

Caso você esteja interessado nos modos menor, maior ou 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
fonte
2

Eu escrevi esta função útil para encontrar o 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
user2975335
fonte
2
Este método falhará se 2 itens tiverem o mesmo número. de ocorrências.
akshaynagpal
2

Curto, mas de alguma forma feio:

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 um dicionário, um pouco menos feio:

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

Um pouco mais, mas pode ter vários modos e obter string com a maioria das contagens ou combinação de tipos de dados.

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

Para um número para ser um mode, deve ocorrer com mais número de vezes que pelo menos um outro número na lista, e deve não ser o único número na lista. Então, refatorei a resposta de @ mathwizurd (para usar o differencemétodo) da seguinte maneira:

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

Esses testes são aprovados com êxito:

mode([]) == None 
mode([1]) == None
mode([1, 1]) == None 
mode([1, 1, 2, 2]) == None 
equilíbrio
fonte
1

Por que não apenas

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

Isso não possui algumas verificações de erro que deveria ter, mas encontrará o modo sem importar nenhuma função e imprimirá uma mensagem se todos os valores aparecerem apenas uma vez. Ele também detectará vários itens que compartilham a mesma contagem máxima, embora não esteja claro se você deseja isso.

lxop
fonte
Então, o que estou tentando fazer é detectar vários itens que exibem a mesma contagem e, em seguida, exibindo todos os itens com essa mesma contagem
bluelantern
Você já tentou isso sozinho? A extensão do meu código aqui para que ele imprima todos os itens com a mesma contagem é bastante simples.
Lxop 31/05
1

Essa função retorna o modo ou modos de uma função, não importa quantos, assim como a frequência do modo ou modos no conjunto de dados. Se não houver modo (ou seja, todos os itens ocorrem apenas uma vez), a função retornará uma sequência de erros. Isso é semelhante à função de A_nagpal acima, mas é, na minha humilde opinião, mais completo, e acho que é mais fácil entender para qualquer iniciante em Python (como o seu verdadeiramente) lendo esta pergunta.

 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
user4406935
fonte
Digo isso apenas porque você disse "a função retorna uma string de erro". A linha que lê return 'There is no mode for this data set. All values occur only once.'pode ser transformada em uma mensagem de erro com a tracebackcondição `se: a próxima linha com recuo aumenta ValueError ('Não há modo para este conjunto de dados. Todos os valores ocorrem apenas uma vez.') Aqui está uma lista de diferentes tipos de erros que você pode gerar.
1

Isso retornará todos os 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
fonte
1

Código simples que localiza o modo da lista sem nenhuma importação:

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)

No caso de vários modos, ele deve retornar o nó mínimo.

baby_yoda
fonte
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
fonte
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
fonte
0

Aqui está uma função simples que obtém o primeiro modo que ocorre em uma lista. Faz um dicionário com os elementos da lista como chaves e número de ocorrências e depois lê os valores de ditado para obter o 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 de Tann
fonte
0

Se você deseja uma abordagem clara, útil para a sala de aula e usando apenas listas e dicionários por compreensão, você pode:

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

fonte
Você deve explicar a sua resposta com comentários ou mais detalhes #
Michael Michael
0

Aqui está como você pode encontrar média, mediana e modo de uma 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
fonte
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
fonte
0

Para quem procura o modo mínimo, por exemplo: caso de distribuição bimodal, usando numpy.

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

O modo de um conjunto de dados é / são os membros que ocorrem com mais freqüência no conjunto. Se houver dois membros que aparecem com mais frequência com o mesmo número de vezes, os dados terão dois modos. Isso é chamado bimodal .

Se houver mais de 2 modos, os dados serão chamados multimodais . Se todos os membros do conjunto de dados aparecerem o mesmo número de vezes, o conjunto de dados não terá nenhum modo .

A função a seguir modes()pode funcionar para encontrar o (s) modo (s) em uma determinada lista de dados:

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

Resultado:

# 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 não queremos importar numpyou pandaschamar qualquer função desses pacotes, para obter essa mesma saída, a modes()função pode ser escrita 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
fonte