Clasificación de elementos múltiples listas por su recuento en Python
Pregunta
Quiero clasificar múltiples listas de acuerdo a sus elementos de la frecuencia con que aparecen en cada lista. Ejemplo:
lista1 = 1,2,3,4
lista2 = 4,5,6,7
list3 = 4,1,8,9
resultado = 4,1,2,3,4,5,6,7,8 (4 se cuenta tres veces, 1 dos veces y el resto una vez)
He intentado lo siguiente pero necesito algo más inteligente y algo que pueda hacer con cualquier ammount de las listas.
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
Ahora aquí está el problema ... i puede hacerlo una y otra vez con A3, A4 y A5 pero es demasiado compleja entonces, necesito una función para esto ... pero no saben cómo ... mi matemáticas se atascó;)
RESUELTO: gracias mucho para la discusión. Como newbee me gusta este sistema de alguna manera: + rápido informativo. Usted me ayudó a todos fuera! Ty
Solución
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)
Ahora vamos a generalizar (para tomar cualquier iterable, afloje requisito hashable), Permitir que la clave e invertir parámetros (para que coincida ordenados), y cambiar el nombre a 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)]
Ejemplo:
>>> 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)]
Otros consejos
La combinación de un par de ideas que ya se ha escrito:
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)]
Notas:
- En Python 2.7, se puede utilizar en lugar de
Counter
defaultdict(int)
. - Esta versión tiene cualquier número de listas como su argumento; el asterisco inicial significa que todos ellos van a ser empaquetados en una tupla. Si desea pasar de una única lista que contiene todas sus listas, que omita asterisco inicial.
- Esto rompe si sus listas contienen un tipo 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)
Prueba con esto:
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)]
Ejemplo de uso:
a = [1,2,3,4]
b = [4,5,6,7]
c = [4,1,8,9]
print rank(a,b,c)
Se puede utilizar cualquier número de listas como entrada
Se puede contar el número de apariciones de cada elemento (un histograma), a continuación, ordenar por él:
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)
Prueba este código:
def elementFreq(myList):
#myList is the list of lists
from collections import Counter
tmp = []
for i in myList: tmp += i
return(Counter(tmp))
Nota: Las listas deben ser de tipo hashable