Classement des éléments de plusieurs listes par leur nombre en Python
Question
Je veux classer plusieurs listes en fonction de leurs éléments à quelle fréquence ils apparaissent dans chaque liste. Exemple:
list1 = 1,2,3,4
liste2 = 4,5,6,7
liste3 = 4,1,8,9
result = 4,1,2,3,4,5,6,7,8 (4 est prise en compte trois fois, 1 fois deux et le reste une fois)
Je l'ai essayé ce qui suit, mais je besoin de quelque chose de plus intelligent et quelque chose que je peux faire avec une ammount des listes.
l = []
l.append([ 1, 2, 3, 4, 5])
l.append([ 1, 9, 3, 4, 5])
l.append([ 1, 10, 8, 4, 5])
l.append([ 1, 12, 13, 7, 5])
l.append([ 1, 14, 13, 13, 6])
x1 = set(l[0]) & set(l[1]) & set(l[2]) & set(l[3])
x2 = set(l[0]) & set(l[1]) & set(l[2]) & set(l[4])
x3 = set(l[0]) & set(l[1]) & set(l[3]) & set(l[4])
x4 = set(l[0]) & set(l[2]) & set(l[3]) & set(l[4])
x5 = set(l[1]) & set(l[2]) & set(l[3]) & set(l[4])
set1 = set(x1) | set(x2) | set(x3) | set(x4) | set(x5)
a1 = list(set(l[0]) & set(l[1]) & set(l[2]) & set(l[3]) & set(l[4]))
a2 = getDifference(list(set1),a1)
print a1
print a2
Maintenant, voici le problème ... je peux le faire encore et encore avec a3, a4 et a5 mais son alors trop complexe, je besoin d'une fonction pour cela ... Mais je ne sais pas comment ... ma mathématiques est resté coincé;)
RESOLU: Merci beaucoup pour la discussion. En tant que newbee j'aime ce système en quelque sorte: rapide + informatif. Vous me aidais tous dehors! Ty
La solution
import collections
data = [
[1, 2, 3, 4, 5],
[1, 9, 3, 4, 5],
[1, 10, 8, 4, 5],
[1, 12, 13, 7, 5],
[1, 14, 13, 13, 6],
]
def sorted_by_count(lists):
counts = collections.defaultdict(int)
for L in lists:
for n in L:
counts[n] += 1
return [num for num, count in
sorted(counts.items(),
key=lambda k_v: (k_v[1], k_v[0]),
reverse=True)]
print sorted_by_count(data)
Maintenant, nous allons généraliser (prendre toute itératives, desserrez exigence hashable), permettent des paramètres clés et inverse (pour correspondre triés), et renomme freq_sorted :
def freq_sorted(iterable, key=None, reverse=False, include_freq=False):
"""Return a list of items from iterable sorted by frequency.
If include_freq, (item, freq) is returned instead of item.
key(item) must be hashable, but items need not be.
*Higher* frequencies are returned first. Within the same frequency group,
items are ordered according to key(item).
"""
if key is None:
key = lambda x: x
key_counts = collections.defaultdict(int)
items = {}
for n in iterable:
k = key(n)
key_counts[k] += 1
items.setdefault(k, n)
if include_freq:
def get_item(k, c):
return items[k], c
else:
def get_item(k, c):
return items[k]
return [get_item(k, c) for k, c in
sorted(key_counts.items(),
key=lambda kc: (-kc[1], kc[0]),
reverse=reverse)]
Exemple:
>>> import itertools
>>> print freq_sorted(itertools.chain.from_iterable(data))
[1, 5, 4, 13, 3, 2, 6, 7, 8, 9, 10, 12, 14]
>>> print freq_sorted(itertools.chain.from_iterable(data), include_freq=True)
# (slightly reformatted)
[(1, 5),
(5, 4),
(4, 3), (13, 3),
(3, 2),
(2, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 1), (12, 1), (14, 1)]
Autres conseils
La combinaison de deux idées déjà affiché:
from itertools import chain
from collections import defaultdict
def frequency(*lists):
counter = defaultdict(int)
for x in chain(*lists):
counter[x] += 1
return [key for (key, value) in
sorted(counter.items(), key=lambda kv: (kv[1], kv[0]), reverse=True)]
Notes:
- En Python 2.7, vous pouvez utiliser
Counter
au lieu dedefaultdict(int)
. - Cette version prend un certain nombre de listes comme argument; l'astérisque signifie qu'ils vont premier tous être emballés dans un tuple. Si vous voulez passer dans une seule liste contenant toutes vos listes, omettre ce premier astérisque.
- Ce casse si vos listes contiennent un type unhashable.
def items_ordered_by_frequency(*lists):
# get a flat list with all the values
biglist = []
for x in lists:
biglist += x
# sort it in reverse order by frequency
return sorted(set(biglist),
key=lambda x: biglist.count(x),
reverse=True)
Essayez celui-ci:
def rank(*lists):
d = dict()
for lst in lists:
for e in lst:
if e in d: d[e] += 1
else: d[e] = 1
return [j[1] for j in sorted([(d[i],i) for i in d], reverse=True)]
Exemple d'utilisation:
a = [1,2,3,4]
b = [4,5,6,7]
c = [4,1,8,9]
print rank(a,b,c)
Vous pouvez utiliser un certain nombre de listes comme entrée
Vous pouvez compter le nombre d'apparitions de chaque élément (un histogramme), puis la trier:
def histogram(enumerable):
result = {}
for x in enumerable:
result.setdefault(x, 0)
result[x] += 1
return result
lists = [ [1,2,3,4], [4,5,6,7], ... ]
from itertools import chain
h = histogram(chain(*lists))
ranked = sorted(set(chain(*lists)), key = lambda x : h[x], reverse = True)
Essayez ce code:
def elementFreq(myList):
#myList is the list of lists
from collections import Counter
tmp = []
for i in myList: tmp += i
return(Counter(tmp))
Note: Vos listes doivent être de type hashable