una tutorial transpuesta tamaño recorrer matriz matrices identidad funciones español ejemplos arreglo python matlab numpy matplotlib

python - tutorial - tamaño de un arreglo numpy



encontrar la longitud de secuencias de valores idénticos en una matriz numpy(codificación de longitud de ejecución) (5)

En un programa pylab (que probablemente también podría ser un programa matlab), tengo una numpy matriz de números que representan distancias: d[t] es la distancia en el tiempo t (y el intervalo de tiempo de mis datos es len(d) unidades de tiempo) .

Los eventos que me interesan son cuando la distancia está por debajo de un cierto umbral, y quiero calcular la duración de estos eventos. Es fácil obtener una matriz de booleanos con b = d<threshold , y el problema se reduce a calcular la secuencia de las longitudes de las palabras True-only en b . Pero no sé cómo hacerlo de manera eficiente (es decir, usando primitivas numpy), y recurrí a caminar la matriz y hacer detección manual de cambios (es decir, inicializar el contador cuando el valor pasa de False a True, aumentar el contador siempre que el valor sea True y saca el contador a la secuencia cuando el valor vuelve a False). Pero esto es tremendamente lento.

¿Cómo detectar eficazmente ese tipo de secuencias en matrices numpy?

Debajo hay un código de Python que ilustra mi problema: el cuarto punto tarda mucho en aparecer (si no, aumenta el tamaño de la matriz)

from pylab import * threshold = 7 print ''.'' d = 10*rand(10000000) print ''.'' b = d<threshold print ''.'' durations=[] for i in xrange(len(b)): if b[i] and (i==0 or not b[i-1]): counter=1 if i>0 and b[i-1] and b[i]: counter+=1 if (b[i-1] and not b[i]) or i==len(b)-1: durations.append(counter) print ''.''


Aquí hay una solución que usa solo arrays: toma una matriz que contiene una secuencia de bools y cuenta la longitud de las transiciones.

>>> from numpy import array, arange >>> b = array([0,0,0,1,1,1,0,0,0,1,1,1,1,0,0], dtype=bool) >>> sw = (b[:-1] ^ b[1:]); print sw [False False True False False True False False True False False False True False] >>> isw = arange(len(sw))[sw]; print isw [ 2 5 8 12] >>> lens = isw[1::2] - isw[::2]; print lens [3 4]

sw contiene un verdadero donde hay un interruptor, isw convierte en índices. Los elementos de isw se restan por pares en la lens .

Tenga en cuenta que si la secuencia comenzara con un 1, contaría la longitud de las secuencias de 0s: esto se puede corregir en la indexación para calcular el objetivo. Además, no he probado casos de esquina tales secuencias de longitud 1.

Función completa que devuelve las posiciones de inicio y las longitudes de todos los subtítulos True .

import numpy as np def count_adjacent_true(arr): assert len(arr.shape) == 1 assert arr.dtype == np.bool if arr.size == 0: return np.empty(0, dtype=int), np.empty(0, dtype=int) sw = np.insert(arr[1:] ^ arr[:-1], [0, arr.shape[0]-1], values=True) swi = np.arange(sw.shape[0])[sw] offset = 0 if arr[0] else 1 lengths = swi[offset+1::2] - swi[offset:-1:2] return swi[offset:-1:2], lengths

Probado para diferentes matrices 1D bool (matriz vacía, elementos individuales / múltiples, longitudes pares / impares, comenzó con True / False , con solo elementos True / False ).


En caso de que alguien tenga curiosidad (y ya que mencionó a MATLAB de paso), aquí hay una manera de resolverlo en MATLAB:

threshold = 7; d = 10*rand(1,100000); % Sample data b = diff([false (d < threshold) false]); durations = find(b == -1)-find(b == 1);

No estoy muy familiarizado con Python, pero tal vez esto podría ayudar a darle algunas ideas. =)


Si bien las numpy no son numpy , itertools funciones de itertools son a menudo muy rápidas, así que haga una prueba (y mida los tiempos para varias soluciones, incluida esta, por supuesto):

def runs_of_ones(bits): for bit, group in itertools.groupby(bits): if bit: yield sum(group)

Si necesita los valores en una lista, simplemente puede usar list (runs_of_ones (bits)), por supuesto; pero tal vez una comprensión de la lista podría ser marginalmente más rápida aún:

def runs_of_ones_list(bits): return [sum(g) for b, g in itertools.groupby(bits) if b]

Pasando a las posibilidades de "numpy-native", ¿qué pasa con:

def runs_of_ones_array(bits): # make sure all runs of ones are well-bounded bounded = numpy.hstack(([0], bits, [0])) # get 1 at run starts and -1 at run ends difs = numpy.diff(bounded) run_starts, = numpy.where(difs > 0) run_ends, = numpy.where(difs < 0) return run_ends - run_starts

De nuevo: ¡asegúrese de comparar soluciones entre sí en ejemplos realistas para usted!


Totalmente nupey vectorizado y genérico RLE para cualquier matriz (funciona con cadenas, booleanos, etc.).

Salidas tuplas de longitudes de ejecución, posiciones de inicio y valores.

import numpy as np def rle(inarray): """ run length encoding. Partial credit to R rle function. Multi datatype arrays catered for including non Numpy returns: tuple (runlengths, startpositions, values) """ ia = np.asarray(inarray) # force numpy n = len(ia) if n == 0: return (None, None, None) else: y = np.array(ia[1:] != ia[:-1]) # pairwise unequal (string safe) i = np.append(np.where(y), n - 1) # must include last element posi z = np.diff(np.append(-1, i)) # run lengths p = np.cumsum(np.append(0, z))[:-1] # positions return(z, p, ia[i])

Bastante rápido (i7):

xx = np.random.randint(0, 5, 1000000) %timeit yy = rle(xx) 100 loops, best of 3: 18.6 ms per loop

Múltiples tipos de datos:

rle([True, True, True, False, True, False, False]) Out[8]: (array([3, 1, 1, 2]), array([0, 3, 4, 5]), array([ True, False, True, False], dtype=bool)) rle(np.array([5, 4, 4, 4, 4, 0, 0])) Out[9]: (array([1, 4, 2]), array([0, 1, 5]), array([5, 4, 0])) rle(["hello", "hello", "my", "friend", "okay", "okay", "bye"]) Out[10]: (array([2, 1, 1, 2, 1]), array([0, 2, 3, 4, 6]), array([''hello'', ''my'', ''friend'', ''okay'', ''bye''], dtype=''|S6''))

Los mismos resultados que Alex Martelli arriba:

xx = np.random.randint(0, 2, 20) xx Out[60]: array([1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1]) am = runs_of_ones_array(xx) tb = rle(xx) am Out[63]: array([4, 5, 2, 5]) tb[0][tb[2] == 1] Out[64]: array([4, 5, 2, 5]) %timeit runs_of_ones_array(xx) 10000 loops, best of 3: 28.5 µs per loop %timeit rle(xx) 10000 loops, best of 3: 38.2 µs per loop

Ligeramente más lento que Alex (pero aún muy rápido), y mucho más flexible.


durations = [] counter = 0 for bool in b: if bool: counter += 1 elif counter > 0: durations.append(counter) counter = 0 if counter > 0: durations.append(counter)