Gibt es eine Standard-Haskell-Entsprechung zu NumPys argsort
-Funktion?Effiziente Haskell-Entsprechung zu NumPys argsort
Ich verwende HMatrix und möchte daher eine Funktion kompatibel mit Vector R
, die ein Alias für Data.Vector.Storable.Vector Double
ist. Die argSort
Funktion unten ist die Implementierung ich zur Zeit mit:
{-# LANGUAGE NoImplicitPrelude #-}
module Main where
import qualified Data.List as L
import qualified Data.Vector as V
import qualified Data.Vector.Storable as VS
import Prelude (($), Double, IO, Int, compare, print, snd)
a :: VS.Vector Double
a = VS.fromList [40.0, 20.0, 10.0, 11.0]
argSort :: VS.Vector Double -> V.Vector Int
argSort xs = V.fromList (L.map snd $ L.sortBy (\(x0, _) (x1, _) -> compare x0 x1) (L.zip (VS.toList xs) [0..]))
main :: IO()
main = print $ argSort a -- yields [2,3,1,0]
ich es klar, nur explizit qualifizierten import
s bin mit machen, wo jede Art und Funktion herkommt.
Diese Implementierung ist nicht besonders effizient, da sie den Eingabevektor in eine Liste und das Ergebnis zurück in einen Vektor konvertiert. Gibt es irgendwo etwas (aber effizienter)?
aktualisieren
@leftaroundabout hatte eine gute Lösung. Dies ist die Lösung, die ich am Ende mit:
module LAUtil.Sorting
(IndexVector
, argSort
)
where
import Control.Monad
import Control.Monad.ST
import Data.Ord
import qualified Data.Vector.Algorithms.Intro as VAI
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import Numeric.LinearAlgebra
type IndexVector = VU.Vector Int
argSort :: Vector R -> IndexVector
argSort xs = runST $ do
let l = VS.length xs
t0 <- VUM.new l
forM_ [0..l - 1] $
\i -> VUM.unsafeWrite t0 i (i, (VS.!) xs i)
VAI.sortBy (comparing snd) t0
t1 <- VUM.new l
forM_ [0..l - 1] $
\i -> VUM.unsafeRead t0 i >>= \(x, _) -> VUM.unsafeWrite t1 i x
VU.freeze t1
Das ist mehr direkt nutzbar mit Numeric.LinearAlgebra
da der Datenvektor ist ein Storable
. Dies verwendet einen ungepackten Vektor für die Indizes.