2016-05-08 9 views
2

Gibt es eine allgemeine Möglichkeit, kleine Werte in einem Array auf Null zu setzen?Wie man kleine Werte in einem Array auf Null setzt?

Mit "klein" meine ich Elemente, deren absoluter Wert kleiner als ein Schwellenwert wie 10.0^-5 ist.

Edit: Für jetzt, ich Schleife mit eachindex.

function sparsify(a, eps) 
    for i in eachindex(a) 
     if abs(a[i]) < eps 
      a[i] = 0 
     end 
    end 
end 

Antwort

5

Warum nicht einfach eine Maske anwenden und ein Element-weise weniger als Operator?

>>> x = rand(Float32, 100) 
>>> eps = 0.5 
>>> x[abs(x) .< eps] = 0 

oder als Funktion (die Funktion beachten Sie modifiziert den Vektor x Inplace):

>>> sparsify!(x, eps) = x[abs(x) .< eps] = 0; 

Sie auch 0 mit zero(eltype(x)), um sicherzustellen, ersetzen könnte es die gleiche Art wie x hat.

Die temporäre Boolean-Maske, die von x .< eps erstellt wurde, vergleicht jedes Element von x mit . Dann wird jedes Element, das diese Bedingung erfüllt, auf 0 gesetzt.

+0

Diese Maske Sache ist interessant. Das Problem war nicht "x.

+0

BTW, ist das Ausrufezeichen eine Konvention für eine Funktion, die ihre Argumente ändert? –

+0

@ Valéry redigierte die Antwort, um 'abs (x)' zu zeigen, bemerkte dieses Detail nicht, danke !. Und ja, [fügt hinzu! zu der Funktion ist eine Namenskonvention] (http://docs.julaulang.org/en/release-0.4/manual/style-guide/#append-to-names-of-functions-that-modify-their-arguments) Beachten Sie, dass die Funktion intern die Parameter ändert. Ist völlig optional, und es gibt mehrere Beiträge in den * Ausgaben * von Github, was darauf hindeutet, dass es in Zukunft entfernt oder geändert wird, aber mittlerweile ist es eine weit verbreitete Konvention (alle julia-Kernfunktionen und die meisten Pakete folgen ihm) . –

1

Ich endete mit einer vektorisierten Methode, die viel kürzer ist.

sparsify(x, eps) = abs(x) < eps ? 0.0 : x 
@vectorize_2arg Float64 sparsify 
1

Welcher Ansatz gewählt wird, hängt davon ab, was Sie benötigen. Wenn Sie nur einen einfachen Einzeiler benötigen, ist die vektorisierte Version in Ordnung. Aber wenn Sie eine optimale Leistung wünschen, wird Ihnen eine Schleife besser helfen.

Hier sind ein paar Alternativen durch die Leistung verglichen. Beachten Sie, dass map in Version 0.4 langsam ist. Die Zeiten hier sind mit Version 0.5 gemacht.

function zerofy!(x, vmin) 
    for (val, i) in enumerate(x) 
     if abs(val) < vmin 
      x[i] = zero(eltype(x)) 
     end 
    end 
end 
zerofy2!(x, vmin) = (x[abs(x) .< vmin] = zero(eltype(x))) 
zerofy3(x, eps) = abs(x) < eps ? 0.0 : x 
@vectorize_2arg Float64 zerofy3! 

zerofy4(y, vmin) = map(x -> abs(x)<vmin ? zero(x) : x, y) 
zerofy4!(y, vmin) = map!(x -> abs(x)<vmin ? zero(x) : x, y) 

function time_zerofy(n, vmin) 
    x1 = rand(n) 
    x2, x3, x4, x5 = copy(x1), copy(x1), copy(x1), copy(x1) 
    @time zerofy!(x1, vmin) 
    @time zerofy2!(x2, vmin) 
    @time zerofy3(x3, vmin) 
    @time zerofy4(x4, vmin) 
    @time zerofy4!(x5, vmin) 
    return nothing 
end 

julia> time_sparse(10^8, 0.1) 
    0.122510 seconds 
    1.078589 seconds (73.25 k allocations: 778.590 MB, 5.42% gc time) 
    0.558914 seconds (2 allocations: 762.940 MB) 
    0.688640 seconds (5 allocations: 762.940 MB) 
    0.243921 seconds 

Es gibt einen ziemlich großen Unterschied zwischen der Schleife (schnellsten) und der Naivität eines vektorisiert.

Bearbeiten: zerofy3! =>zerofy3 da es nicht in-Place ist.

+0

Danke für das Benchmarking der Alternativen. –

Verwandte Themen