高效的Haskell相当于NumPy的argsort

时间:2016-11-13 17:44:34

标签: haskell numpy hmatrix

是否有标准的Haskell等同于NumPy的argsort函数?

我使用HMatrix,因此,希望功能与Vector R兼容,Data.Vector.Storable.Vector DoubleargSort的别名。以下{-# 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] 功能是我目前正在使用的实现:

import

我使用显式限定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 只是为了清楚说明每种类型和功能的来源。

这种实现效率不是很高,因为它将输入向量转换为列表,并将结果转换回向量。在某个地方存在这样的事情(但效率更高)吗?

更新

@leftaroundabout有一个很好的解决方案。这是我最终得到的解决方案:

Numeric.LinearAlgebra

由于数据向量为Storable,因此可以更直接地与allow(AuthorizeApiRequest).to receive_message_chain(:call, :result).and_return(user) 一起使用。这为索引使用了未装箱的矢量。

2 个答案:

答案 0 :(得分:5)

使用vector-algorithms

import Data.Ord (comparing)

import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Algorithms.Intro as VAlgo

argSort :: (Ord a, VU.Unbox a) => VU.Vector a -> VU.Vector Int
argSort xs = VU.map fst $ VU.create $ do
    xsi <- VU.thaw $ VU.indexed xs
    VAlgo.sortBy (comparing snd) xsi
    return xsi

请注意,这些是Unboxed而不是Storable向量。后者需要做出一些权衡以允许不纯的C FFI操作,并且无法正确处理异构元组。你当然可以convert来往于可存储的载体。

答案 1 :(得分:0)

对我来说更好的是使用Data.map,因为它受列表融合,加快了速度。这里n =长度xs。

import Data.Map as M (toList, fromList, toAscList)

    out :: Int -> [Double] -> [Int]
    out n !xs = let !a=  (M.toAscList (M.fromList $! (zip xs [0..n])))
                    !res=a `seq` L.map snd a
                in res

然而,这只适用于定期列表,如:

out 12 [1,2,3,4,1,2,3,4,1,2,3,4] == out 12 [1,2,3,4,1,3,2,4,1,2,3,4]