2012-06-21 3 views
2

pour pouvoir travailler avec des listes bimodale etc.Quel est le moyen le plus efficace pour trouver les valeurs modales d'une liste?

mes Tentatives jusqu'à présent:

testlist = [1,2,3,3,2,1,4,2,2,3,4,3,3,4,5,3,2,4,55,6,7,4,3,45,543,4,53,4,53,234] 

.

from collections import Counter 

def modal_1(xs): 
    cntr = Counter(xs).most_common() 
    val,count = cntr[0] 
    return (v for v,c in cntr if c is count) 

print(list(modal_1(testlist))) 
>>> [3, 4] 

- ou peut-être quelque chose comme -

def modal_2(xs): 
     cntr = Counter(xs).most_common() 
     val,count = cntr[0] 
     return takewhile(lambda x: x[1] is count, cntr) 

print(list(modal_2(testlist))) 
>>> [(3, 7), (4, 7)] 

S'il vous plaît ne pas répondre - utiliser numpy etc.

Note:

Counter(xs).most_common(1)

renvoie le premier ' modal 'de n valeurs modales. S'il y en a deux. Cela ne retournera que le premier. Ce qui est une honte ... parce que cela rendrait cela beaucoup plus facile. Ok, donc j'étais vraiment surpris que l'une de mes options d'origine est en fait un bon moyen de le faire. Pour ceux qui veulent maintenant trouver n nombres modaux dans une liste, je suggère les options suivantes. Ces deux fonctions fonctionnent bien sur les listes avec plus de 1000 valeurs

Toutes ces listes renvoient à (nombre, nombre), où nombre sera identique pour tous les tuples. Je pense qu'il est préférable d'avoir cela et ensuite l'analyser au désir de votre cœur.

utilisant TakeWhile:

from collections import Counter 
from itertools import takewhile 

def modal_3(xs): 
    counter = Counter(xs).most_common() 
    mx = counter[0][1] 
    return takewhile(lambda x: x[1] == mx, counter) 

print(list(modal_3(testlist))) 
>>> [(3, 7), (4, 7)] 

utilisant groupby:

from collections import Counter 
from itertools import groupby 
from operator import itemgetter 

def modal_4(xs):  
    container = Counter(xs) 
    return next(groupby(container.most_common(), key=itemgetter(1)))[1] 

print(list(modal_4(testlist))) 
>>> [(3, 7), (4, 7)] 

et la finale, pythonique et moyen le plus rapide:

def modal_5(xs): 

    def _mode(xs): 
     for x in xs: 
      if x[1] != xs[0][1]: 
       break 
      yield x 

    counter = collections.Counter(xs).most_common() 

    return [ x for x in _mode(counter) ] 

merci vous à tous pour l'aide et l'information .

+0

Cela fait beaucoup d'ellipse. Les périodes ont besoin d'amour aussi. – TheZ

+0

Je pensais que ça rendait la question plus ... ouverte. – beoliver

+0

Désolé, je ne vois pas pourquoi 'Counter.most_common (1)' ne le fait pas pour vous? –

Répondre

3

Je pense que votre deuxième exemple est le mieux, avec quelques modifications mineures:

from itertools import takewhile 
from collections import Counter 

def modal(xs): 
     counter = Counter(xs).most_common() 
     _, count = counter[0] 
     return takewhile(lambda x: x[1] == count, counter) 

Le changement est ici d'utiliser == plutôt que is-is vérifie l'identité, qui, tout en vrai pour certaines valeurs comme Python fait un peu magie avec int s en arrière-plan pour les mettre en cache, ne sera pas toujours tout le temps, et ne devrait pas être invoqué dans ce cas.

>>> a = 1 
>>> a is 1 
True 
>>> a = 300 
>>> a is 300 
False 
+0

En fait, j'ai changé le code à, car je pensais que les gens se plaindraient de '==' Oh bien;) – beoliver

+0

'is' devrait plutôt être utilisé uniquement lors de la vérification de l'identité, et le seul moment commun que vous voulez faire est contre 'None'. –

+0

ah oui! cela me semble familier. – beoliver

2
>>> testlist = [1,2,3,3,2,1,4,2,2,3,4,3,3,4,5,3,2,4,55,6,7,4,3,45,543,4,53,4,53,234] 
>>> dic={x:testlist.count(x) for x in set(testlist)} 

>>> [x for x in dic if dic[x]==max(dic.values())] 

[3, 4] 
+1

-1 - Je ne vois aucune raison de réimplémenter 'collections.Counter()' avec quelque chose de beaucoup moins efficace ici. –

+0

@Lattyware: D'accord, mais 'max (cntr.values ​​())' (sur un compteur) fonctionnerait aussi, et cela semble plus élégant que 'val, count = cntr [0]' – Junuxx

+0

@Junuxx Pas vraiment, Comme Counter nous donnera des résultats ordonnés, si nous faisons 'max()', nous effectuons une nouvelle recherche dans la liste sans aucune raison. –

2

Quoi? takewhile mais pas groupby?

>>> from collections import Counter 
>>> testlist = [1,2,3,3,2,1,4,2,2,3,4,3,3,4,5,3,2,4,55,6,7,4,3,45,543,4,53,4,53,234] 
>>> cntr = Counter(testlist) 
>>> from itertools import groupby 
>>> list(x[0] for x in next(groupby(cntr.most_common(), key=lambda x:x[1]))[1]) 
[3, 4] 
+0

Oi! Je relis mon pdf de bibliothèque de python en tant que je parle! – beoliver

+0

donc cela signifie que dès que la clé change, la liste est complète? 'Il génère une pause ou un nouveau groupe chaque fois que la valeur de la fonction clé change – beoliver

+0

presque aussi vite que prenante :) – beoliver

Questions connexes