web-dev-qa-db-fra.com

Le moyen le plus rapide de mettre à zéro les valeurs faibles dans le tableau?

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]
34
David

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 .

76
Eric O Lebigot
from scipy.stats import threshold
thresholded = threshold(array, 0.5)

:)

19
omygaudio

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.

Documents sur les tableaux masqués dans numpy

7
Alexander Lebedev

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

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
6
jfs

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.

5
Greg Hewgill

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.

2
digitalarbeiter

Vous pouvez utiliser map et lambda, cela devrait être assez rapide.

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

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]
0
Matt Anderson