2009-10-26 5 views
34

Entonces, digamos que tengo 100.000 matrices flotantes con 100 elementos cada una. Necesito el mayor número de valores de X, PERO solo si son mayores que Y. Cualquier elemento que no coincida con esto debe establecerse en 0. ¿Cuál sería la forma más rápida de hacer esto en Python? El orden debe mantenerse. La mayor parte de los elementos que ya se ponen a 0.¿La forma más rápida de poner a cero valores bajos en el conjunto?

variables de muestra: resultado

array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0] 
highCountX = 3 
lowValY = .1 

esperada:

array = [0, .25, 0, .15, .5, 0, 0, 0, 0, 0] 
+0

¿Cuál es HightCountX se para? –

+0

highCountX es la cantidad máxima de elementos distintos de cero que deseo que existan en la matriz – David

+0

Si fuera 2 el resultado esperado sería: [0, 0, 0, .15, .5, 0, 0, 0, 0, 0] - highCountX limita el número de elementos distintos de cero en el resultado. – Abgan

Respuesta

73

Este es un trabajo típico para NumPy, que es muy rápido para este tipo de operaciones:

array_np = numpy.asarray(array) 
low_values_flags = array_np < lowValY # Where values are low 
array_np[low_values_flags] = 0 # All low values set to 0 

Ahora, si sólo necesita los highCountX elementos más grandes, incluso se puede "olvidar" los elementos pequeños (en lugar de establecer a 0 y clasificación de ellos) y sólo ordenar la lista de elementos de grandes dimensiones:

array_np = numpy.asarray(array) 
print numpy.sort(array_np[array_np >= lowValY])[-highCountX:] 

Por supuesto, la clasificación toda la matriz si sólo necesita unos pocos elementos podrían no ser óptima. Dependiendo de sus necesidades, es posible que desee considerar el módulo estándar heapq.

+5

Bueno ... usar las bibliotecas adecuadas puede llevarte muy lejos :-) – Abgan

+0

Me sigo encontrando con este número, supongo que tendré que echarle un vistazo :) Gracias por la ayuda (a todos). – David

+0

@David NumPy realmente satisface una necesidad. Sugiero que comiences con el tutorial al que me he vinculado: probablemente sea la forma más rápida de ponerte al día con NumPy y aprender sus conceptos más importantes. – EOL

5

La forma más sencilla sería:

topX = sorted([x for x in array if x > lowValY], reverse=True)[highCountX-1] 
print [x if x >= topX else 0 for x in array] 

En pedazos, esto selecciona todos los elementos mayores que lowValY:

[x for x in array if x > lowValY] 

Esta matriz contiene solamente el número de elementos mayor que el umbral. Entonces, su clasificación por lo que los valores más altos se encuentran en el inicio:

sorted(..., reverse=True) 

entonces un índice de lista toma el umbral para los highCountX principales elementos:

sorted(...)[highCountX-1] 

Por último, la matriz original se llena a cabo usando otro comprensión de lista:

[x if x >= topX else 0 for x in array] 

hay una condición de frontera, donde hay dos o más elementos que la igualdad (en el ejemplo) son los elementos más altos 3er. La matriz resultante contendrá ese elemento más de una vez.

También existen otras condiciones de contorno, como por ejemplo len(array) < highCountX. El manejo de tales condiciones queda en manos del implementador.

+1

Puede usar x para x en la matriz si x> lowVALY en lugar de [x para x en la matriz si x> lowVALY] solo para enumerar la matriz original sin copiarla (si los datos originales son bastante grandes, esto podría ser una buena cosa para hacer) – Abgan

+1

Eso es verdad. 'sorted()' probablemente necesite toda la lista de todos modos. –

+0

Heh, 3 veces más rápido que mi código novato, pero necesitaría los elementos iguales para mantener el límite de highCountX. Las matrices deben tener entre 20 y 200 elementos ... en realidad son segmentos de una matriz más grande que proceso en trozos. Gracias por la ayuda hasta ahora. – David

2

elementos ajustes por debajo de algún umbral a cero es fácil: (., Más la abs ocasional() si es necesario)

array = [ x if x > threshold else 0.0 for x in array ] 

El requisito de los números más altos n es un poco vago, sin embargo. ¿Qué pasa si hay, por ejemplo, N + 1 números iguales por encima del umbral? ¿Cuál truncar?

Usted puede ordenar la matriz en primer lugar, a continuación, establecer el umbral para el valor del elemento enésimo:

threshold = sorted(array, reverse=True)[N] 
array = [ x if x >= threshold else 0.0 for x in array ] 

Nota: esta solución está optimizado para facilitar la lectura no el rendimiento.

+0

en este caso, no importa cuál se trunca ... más importante es que se sigue highCountX – David

6

Usando numpy:

# assign zero to all elements less than or equal to `lowValY` 
a[a<=lowValY] = 0 
# find n-th largest element in the array (where n=highCountX) 
x = partial_sort(a, highCountX, reverse=True)[:highCountX][-1] 
# 
a[a<x] = 0 #NOTE: it might leave more than highCountX non-zero elements 
      # . if there are duplicates 

Dónde partial_sort podrían ser:

def partial_sort(a, n, reverse=False): 
    #NOTE: in general it should return full list but in your case this will do 
    return sorted(a, reverse=reverse)[:n] 

La expresión a[a<value] = 0 se puede escribir sin numpy de la siguiente manera:

for i, x in enumerate(a): 
    if x < value: 
     a[i] = 0 
1

Usted puede utilizar el mapa y lambda , debe ser rápido e nough.

new_array = map(lambda x: x if x>y else 0, array) 
0

Usa un heap.

Esto funciona en el tiempo O(n*lg(HighCountX)).

import heapq 

heap = [] 
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0] 
highCountX = 3 
lowValY = .1 

for i in range(1,highCountX): 
    heappush(heap, lowValY) 
    heappop(heap) 

for i in range(0, len(array) - 1) 
    if array[i] > heap[0]: 
     heappush(heap, array[i]) 

min = heap[0] 

array = [x if x >= min else 0 for x in array] 

deletemin trabaja en el montón O(lg(k)) e inserción O(lg(k)) o O(1) dependiendo de qué tipo de pila que utiliza.

+0

no se prueba la sintaxis del código ... – Egon

7

Hay una clase especial MaskedArray en NumPy que hace exactamente eso. Puede "enmascarar" elementos en función de cualquier precondición. Esto representa mejor su necesidad que la asignación de ceros: las operaciones numpy ignorarán los valores enmascarados cuando corresponda (por ejemplo, encontrar el valor medio).

>>> from numpy import ma 
>>> x = ma.array([.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]) 
>>> x1 = ma.masked_inside(0, 0.1) # mask everything in 0..0.1 range 
>>> x1 
masked_array(data = [-- 0.25 -- 0.15 0.5 -- -- -- -- --], 
     mask = [ True False True False False True True True True True], 
    fill_value = 1e+20) 
>>> print x.filled(0) # Fill with zeroes 
[ 0 0.25 0 0.15 0.5 0 0 0 0 0 ] 

Como beneficio addded, matrices enmascarados están bien soportados en la librería de visualización matplotlib si necesita esto.

Docs on masked arrays in numpy

0

El uso de un montón de piedras es una buena idea, como dice Egon. Pero se puede utilizar la función heapq.nlargest para reducir en un poco de esfuerzo:

import heapq 

array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0] 
highCountX = 3 
lowValY = .1 

threshold = max(heapq.nlargest(highCountX, array)[-1], lowValY) 
array = [x if x >= threshold else 0 for x in array] 
+0

Me gusta esta solución casera que solo usa módulos estándar. Sin embargo, debe actualizarse para devolver realmente los elementos highCountX más grandes (si muchos elementos en la matriz tienen el valor 'threshold', la matriz final tiene demasiados elementos distintos de cero). – EOL

19
from scipy.stats import threshold 
thresholded = threshold(array, 0.5) 

:)

Cuestiones relacionadas