tutorial print matrices array python search numpy

matrices - print matrix python



Encuentre un gran número de valores consecutivos que cumplan la condición en una matriz numpy (7)

@ joe-kington Tengo una mejora de velocidad de aproximadamente 20% -25% sobre la solución np.diff / np.nonzero utilizando argmax lugar (consulte el código siguiente, la condition es booleana)

def contiguous_regions(condition): idx = [] i = 0 while i < len(condition): x1 = i + condition[i:].argmax() try: x2 = x1 + condition[x1:].argmin() except: x2 = x1 + 1 if x1 == x2: if condition[x1] == True: x2 = len(condition) else: break idx.append( [x1,x2] ) i = x2 return idx

Por supuesto, su kilometraje puede variar dependiendo de sus datos.

Además, no estoy del todo seguro, pero supongo que numpy puede optimizar argmin/argmax sobre matrices booleanas para detener la búsqueda en la primera aparición de True/False . Eso podría explicarlo.

Tengo algunos datos de audio cargados en una matriz numpy y deseo segmentar los datos encontrando partes silenciosas, es decir, partes donde la amplitud de audio está por debajo de un cierto umbral durante un período de tiempo.

Una forma extremadamente simple de hacer esto es algo como esto:

values = ''''.join(("1" if (abs(x) < SILENCE_THRESHOLD) else "0" for x in samples)) pattern = re.compile(''1{%d,}''%int(MIN_SILENCE)) for match in pattern.finditer(values): # code goes here

El código anterior encuentra partes donde hay al menos MIN_SILENCE elementos consecutivos más pequeños que SILENCE_THRESHOLD.

Ahora, obviamente, el código anterior es horriblemente ineficiente y un terrible abuso de las expresiones regulares. ¿Hay algún otro método que sea más eficiente, pero que resulte en un código igualmente simple y corto?


Aquí hay una solución basada en números.

Creo que (?) Debería ser más rápido que las otras opciones. Esperemos que sea bastante claro.

Sin embargo, requiere el doble de memoria que las diversas soluciones basadas en generadores. Siempre que pueda mantener una sola copia temporal de sus datos en la memoria (para el diff), y una matriz booleana de la misma longitud que sus datos (1 bit por elemento), debería ser bastante eficiente ...

import numpy as np def main(): # Generate some random data x = np.cumsum(np.random.random(1000) - 0.5) condition = np.abs(x) < 1 # Print the start and stop indicies of each region where the absolute # values of x are below 1, and the min and max of each of these regions for start, stop in contiguous_regions(condition): segment = x[start:stop] print start, stop print segment.min(), segment.max() def contiguous_regions(condition): """Finds contiguous True regions of the boolean array "condition". Returns a 2D array where the first column is the start index of the region and the second column is the end index.""" # Find the indicies of changes in "condition" d = np.diff(condition) idx, = d.nonzero() # We need to start things after the change in "condition". Therefore, # we''ll shift the index by 1 to the right. idx += 1 if condition[0]: # If the start of condition is True prepend a 0 idx = np.r_[0, idx] if condition[-1]: # If the end of condition is True, append the length of the array idx = np.r_[idx, condition.size] # Edit # Reshape the result into two columns idx.shape = (-1,2) return idx main()


Esto debería devolver una lista de pares (start,length) :

def silent_segs(samples,threshold,min_dur): start = -1 silent_segments = [] for idx,x in enumerate(samples): if start < 0 and abs(x) < threshold: start = idx elif start >= 0 and abs(x) >= threshold: dur = idx-start if dur >= min_dur: silent_segments.append((start,dur)) start = -1 return silent_segments

Y una prueba sencilla:

>>> s = [-1,0,0,0,-1,10,-10,1,2,1,0,0,0,-1,-10] >>> silent_segs(s,2,2) [(0, 5), (9, 5)]


Hay una solución muy conveniente para esto usando scipy.ndimage . Para una matriz:

a = array([1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0])

que puede ser el resultado de una condición aplicada a otra matriz, encontrar las regiones contiguas es tan simple como:

regions = scipy.ndimage.find_objects(scipy.ndimage.label(a)[0])

Luego, se puede aplicar cualquier función a esas regiones, por ejemplo, como:

[np.sum(a[r]) for r in regions]


Ligeramente descuidado, pero simple y rápido, si no te importa usar scipy:

from scipy.ndimage import gaussian_filter sigma = 3 threshold = 1 above_threshold = gaussian_filter(data, sigma=sigma) > threshold

La idea es que las partes silenciosas de los datos se suavizarán a una amplitud baja, y las regiones ruidosas no. Sintonice ''sigma'' para afectar la duración de una región ''tranquila''; sintonice el ''umbral'' para afectar lo silencioso que debe ser. Esto se ralentiza para sigma grande, en cuyo momento el uso de suavizado basado en FFT podría ser más rápido.

Esto tiene la ventaja añadida de que los "píxeles calientes" individuales no interrumpirán su búsqueda de silencio, por lo que es un poco menos sensible a ciertos tipos de ruido.


No he probado esto, pero usted debería estar cerca de lo que está buscando. Un poco más de líneas de código, pero debería ser más eficiente, legible y no abusar de las expresiones regulares :-)

def find_silent(samples): num_silent = 0 start = 0 for index in range(0, len(samples)): if abs(samples[index]) < SILENCE_THRESHOLD: if num_silent == 0: start = index num_silent += 1 else: if num_silent > MIN_SILENCE: yield samples[start:index] num_silent = 0 if num_silent > MIN_SILENCE: yield samples[start:] for match in find_silent(samples): # code goes here


otra forma de hacerlo de forma rápida y concisa:

import pylab as pl v=[0,0,1,1,0,0,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,0,0] vd = pl.diff(v) #vd[i]==1 for 0->1 crossing; vd[i]==-1 for 1->0 crossing #need to add +1 to indexes as pl.diff shifts to left by 1 i1=pl.array([i for i in xrange(len(vd)) if vd[i]==1])+1 i2=pl.array([i for i in xrange(len(vd)) if vd[i]==-1])+1 #corner cases for the first and the last element if v[0]==1: i1=pl.hstack((0,i1)) if v[-1]==1: i2=pl.hstack((i2,len(v)))

ahora i1 contiene el índice inicial y i2 el índice final de 1, ..., 1 áreas