Question

Disons que j’ai 100 000 tableaux de flotteurs de 100 éléments chacun. J'ai besoin du plus grand nombre de valeurs X, MAIS si elles sont supérieures à Y. Tout élément ne correspondant pas doit être mis à 0. Quel serait le moyen le 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]
Était-ce utile?

La solution

C’est un travail typique pour NumPy , ce 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 éléments les plus grands de highCountX, vous pouvez même & "oublier &"; les petits éléments (au lieu de les mettre à 0 et de les trier) et de ne trier que la liste des grands éléments:

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

Bien sûr, trier l’ensemble du tableau si vous n’avez besoin que de quelques éléments peut ne pas être optimal. Selon vos besoins, vous pouvez envisager le module heapq standard.

Autres conseils

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

:

Il existe une classe spéciale MaskedArray dans NumPy qui fait exactement cela. Vous pouvez & Quot; masquer & Quot; éléments basés sur une 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.

Docs sur des tableaux masqués numpy

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 écrite sans <=> comme suit:

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

Le moyen le 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érieurs au seuil. Ensuite, triez les valeurs les plus grandes au début:

sorted(..., reverse=True)

Ensuite, un index de liste prend le seuil pour les premiers highCountX éléments:

sorted(...)[highCountX-1]

Enfin, le tableau d'origine est rempli à l'aide d'une autre compréhension de la liste:

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

Il existe une condition limite dans laquelle il y a deux ou plusieurs éléments égaux qui (dans votre exemple) sont les 3ème plus hauts éléments. Le tableau résultant contiendra cet élément plusieurs fois.

Il existe également d'autres conditions aux limites, telles que si len(array) < highCountX. Le traitement de telles conditions est laissé à l’implémenteur.

Les éléments de configuration dont le seuil est égal à zéro sont faciles:

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

(plus l'abs occasionnel () si nécessaire.)

L’exigence des N nombres les plus élevés est toutefois un peu vague. Et s'il y a par exemple N + 1 numéros égaux au-dessus du seuil? Lequel tronquer?

Vous pouvez d'abord trier le tableau, puis définir le seuil sur la valeur du Niè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 la performance.

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

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

Utilisez un segment de mémoire .

Cela fonctionne dans le temps 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 fonctionne dans le segment de mémoire O(lg(k)) et l'insertion O(1) ou <=> en fonction du type de segment de mémoire que vous utilisez.

Utiliser un tas est une bonne idée, comme dit Egon. Mais vous pouvez utiliser la fonction heapq.nlargest pour réduire vos 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]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top