¿Cuál es la forma más rápida de comparar dos listas grandes de 1 y 0 y devolver el recuento / porcentaje de diferencia?

Necesito un método para devolver rápidamente el número de diferencias entre dos listas grandes. El contenido de cada elemento de la lista es 1 o 0 (enteros únicos) y la cantidad de elementos en cada lista siempre será 307200.

Esta es una muestra de mi código actual:

list1 =  # should be a list of integers containing 1's or 0's list2 =  # same rule as above, in a slightly different order diffCount = 0 for index, item in enumerate(list1): if item != list2[index]: diffCount += 1 percent = float(diffCount) / float(307200) 

Lo anterior funciona pero es demasiado lento para mis propósitos. Lo que me gustaría saber es si hay una forma más rápida de obtener el número de diferencias entre listas o el porcentaje de elementos que difieren.

He visto algunos hilos similares en este sitio, pero todos parecen funcionar un poco diferente de lo que quiero, y los ejemplos de set () no parecen funcionar para mis propósitos. :PAG

Puede obtener al menos otra aceleración de 10X si utiliza matrices NumPy en lugar de listas.

 import random import time import numpy as np list1 = [random.choice((0,1)) for x in xrange(307200)] list2 = [random.choice((0,1)) for x in xrange(307200)] a1 = np.array(list1) a2 = np.array(list2) def foo1(): start = time.clock() counter = 0 for i in xrange(307200): if list1[i] != list2[i]: counter += 1 print "%d, %f" % (counter, time.clock()-start) def foo2(): start = time.clock() ct = np.sum(a1!=a2) print "%d, %f" % (ct, time.clock()-start) foo1() #153490, 0.096215 foo2() #153490, 0.010224 

Si es posible, use la respuesta de Paul / JayP de usar numpy (con xor), si solo puede usar la plataforma estándar de python, el contenido de la lista de componentes de itertools parece ser el más rápido:

 import random import time import numpy import itertools list1 = [random.choice((0,1)) for x in xrange(307200)] list2 = [random.choice((0,1)) for x in xrange(307200)] a1 = numpy.array(list1) a2 = numpy.array(list2) def given(): diffCount = 0 for index, item in enumerate(list1): if item != list2[index]: diffCount += 1 return diffCount def xrange_iter(): counter = 0 for i in xrange(len(list1)): if list1[i] != list2[i]: counter += 1 return counter def np_not_eq(): return numpy.sum(a1!=a2) def np_xor(): return numpy.sum(a1^a2) def np_not_eq_plus_array(): arr1 = numpy.array(list1) arr2 = numpy.array(list2) return numpy.sum(arr1!=arr2) def np_xor_plus_array(): arr1 = numpy.array(list1) arr2 = numpy.array(list2) return numpy.sum(arr1^arr2) def enumerate_comprehension(): return len([0 for i,x in enumerate(list1) if x != list2[i]]) def izip_comprehension(): return len([0 for a,b in itertools.izip(list1, list2) if a != b]) def zip_comprehension(): return len([0 for a,b in zip(list1, list2) if a != b]) def functional(): return sum(map(lambda (a,b): a^b, zip(list1,list2))) def bench(func): diff = [] for i in xrange(100): start = time.clock() result = func() stop = time.clock() diff.append(stop - start) print "%25s -- %d, %f" % (func.__name__, result, sum(diff)/float(len(diff))) bench(given) bench(xrange_iter) bench(np_not_eq) bench(np_xor) bench(np_not_eq_plus_array) bench(np_xor_plus_array) bench(enumerate_comprehension) bench(zip_comprehension) bench(izip_comprehension) bench(functional) 

Conseguí esto (en Python 2.7.1, Snow Leopard):

  given -- 153618, 0.046746 xrange_iter -- 153618, 0.049081 np_not_eq -- 153618, 0.003069 np_xor -- 153618, 0.001869 np_not_eq_plus_array -- 153618, 0.081671 np_xor_plus_array -- 153618, 0.080536 enumerate_comprehension -- 153618, 0.037587 zip_comprehension -- 153618, 0.083983 izip_comprehension -- 153618, 0.034506 functional -- 153618, 0.117359 

Realmente no sé si esto es más rápido, pero podría experimentar con algunos de los métodos “funcionales” que ofrece python. Por lo general, es mejor que los bucles se ejecuten mediante subrutinas internas codificadas a mano.

Algo como esto:

 diffCount = sum(map(lambda (a,b): a^b, zip(list1,list2))) 
 >>> import random >>> import time >>> list1 = [random.choice((0,1)) for x in xrange(307200)] >>> list2 = [random.choice((0,1)) for x in xrange(307200)] >>> def foo(): ... start = time.clock() ... counter = 0 ... for i in xrange(307200): ... if list1[i] != list2[i]: ... counter += 1 ... print "%d, %f" % (counter, time.clock()-start) ... >>> foo() 153901, 0.068593 

¿Es 7 centésimas de segundo demasiado lento para su aplicación?

También probaría el siguiente método stdlib-only:

 import itertools as it, operator as op def list_difference_count(list1, list2): return sum(it.starmap(op.ne, it.izip(list1, list2))) >>> list_difference_count([1, 2, 3, 4], [1, 2, 1, 2]) 2 

Esto funciona correctamente para len(list1) == len(list2) . Si está seguro de que los elementos de la lista son siempre enteros, puede sustituir op.xor por op.ne (podría mejorar el rendimiento).

El porcentaje de diferencia es: float(list_difference_count(l1, l2))/len(l1) .