Donc, disons que j'ai 100 000 tableaux flottants avec 100 éléments chacun. J'ai besoin du nombre X le plus élevé de valeurs, MAIS seulement si elles sont supérieures à Y. Tout élément ne correspondant pas à cela devrait être défini sur 0. Quelle serait la façon la plus rapide de le faire en Python? L'ordre doit être maintenu. La plupart des éléments sont déjà définis sur 0.
exemples de variables:
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]
highCountX = 3
lowValY = .1
résultat attendu:
array = [0, .25, 0, .15, .5, 0, 0, 0, 0, 0]
C'est un travail typique pour NumPy , qui est très rapide pour ces types d'opérations:
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
Maintenant, si vous n'avez besoin que des plus grands éléments highCountX, vous pouvez même "oublier" les petits éléments (au lieu de les mettre à 0 et de les trier) et trier uniquement la liste des grands éléments:
array_np = numpy.asarray(array)
print numpy.sort(array_np[array_np >= lowValY])[-highCountX:]
Bien sûr, le tri de l'ensemble du tableau si vous n'avez besoin que de quelques éléments peut ne pas être optimal. Selon vos besoins, vous voudrez peut-être envisager le module standard heapq .
from scipy.stats import threshold
thresholded = threshold(array, 0.5)
:)
Il y a une classe MaskedArray spéciale dans NumPy qui fait exactement cela. Vous pouvez "masquer" les éléments en fonction de n'importe quelle condition préalable. Cela représente mieux votre besoin que d'attribuer des zéros: les opérations numpy ignoreront les valeurs masquées le cas échéant (par exemple, trouver la valeur moyenne).
>>> 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 ]
Comme avantage supplémentaire, les tableaux masqués sont bien pris en charge dans la bibliothèque de visualisation matplotlib si vous en avez besoin.
Utilisation de 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
Où partial_sort
pourrait être:
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]
L'expression a[a<value] = 0
peut être écrit sans numpy
comme suit:
for i, x in enumerate(a):
if x < value:
a[i] = 0
La manière la plus simple serait:
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 morceaux, cela sélectionne tous les éléments supérieurs à lowValY
:
[x for x in array if x > lowValY]
Ce tableau contient uniquement le nombre d'éléments supérieur au seuil. Ensuite, triez-le afin que les plus grandes valeurs soient au début:
sorted(..., reverse=True)
Ensuite, un index de liste prend le seuil pour les éléments highCountX
supérieurs:
sorted(...)[highCountX-1]
Enfin, le tableau d'origine est rempli à l'aide d'une autre compréhension de liste:
[x if x >= topX else 0 for x in array]
Il y a une condition aux limites où il y a deux ou plusieurs éléments égaux qui (dans votre exemple) sont les 3e éléments les plus élevés. Le tableau résultant contiendra cet élément plus d'une fois.
Il existe également d'autres conditions aux limites, telles que if len(array) < highCountX
. La gestion de ces conditions est laissée à l'implémentateur.
La configuration des éléments en dessous d'un certain seuil à zéro est facile:
array = [ x if x > threshold else 0.0 for x in array ]
(plus les abs occasionnels () si nécessaire.)
L'exigence des N nombres les plus élevés est cependant un peu vague. Et s'il y a par exemple N + 1 nombres égaux au-dessus du seuil? Lequel tronquer?
Vous pouvez d'abord trier le tableau, puis définir le seuil sur la valeur du Nème élément:
threshold = sorted(array, reverse=True)[N]
array = [ x if x >= threshold else 0.0 for x in array ]
Remarque: cette solution est optimisée pour la lisibilité et non pour les performances.
Vous pouvez utiliser map et lambda, cela devrait être assez rapide.
new_array = map(lambda x: x if x>y else 0, array)
Utiliser un tas est une bonne idée, comme le dit egon. Mais vous pouvez utiliser le heapq.nlargest
fonction pour réduire certains efforts:
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]