【问题标题】:How to implement "where" (numpy.where(...) )?如何实现“哪里”(numpy.where(...))?
【发布时间】:2011-12-18 20:45:40
【问题描述】:

我是一个函数式编程新手。 我想知道如何在 python、scala 或 haskell 中实现 numpy.where() 。 一个好的解释会对我有所帮助。

【问题讨论】:

    标签: python scala haskell functional-programming numpy


    【解决方案1】:

    在 Haskell 中,为 n 维列表做这件事,正如 NumPy 等价物所支持的那样,需要相当高级的类型类构造,但一维的情况很容易:

    select :: [Bool] -> [a] -> [a] -> [a]
    select [] [] [] = []
    select (True:bs) (x:xs) (_:ys) = x : select bs xs ys
    select (False:bs) (_:xs) (y:ys) = y : select bs xs ys
    

    这只是一个简单的递归过程,依次检查每个列表的每个元素,并在每个列表到达末尾时生成空列表。 (请注意,这些是列表,而不是数组。)

    这是一个更简单但不太明显的一维列表实现,翻译了 NumPy 文档中的定义(感谢 joaquin 指出):

    select :: [Bool] -> [a] -> [a] -> [a]
    select bs xs ys = zipWith3 select' bs xs ys
      where select' True x _ = x
            select' False _ y = y
    

    为了实现两个参数的情况(返回条件为 True 的所有索引;感谢 Rex Kerr 指出这种情况),可以使用列表推导:

    trueIndices :: [Bool] -> [Int]
    trueIndices bs = [i | (i,True) <- zip [0..] bs]
    

    也可以用现有的select 写,虽然没什么意义:

    trueIndices :: [Bool] -> [Int]
    trueIndices bs = catMaybes $ select bs (map Just [0..]) (repeat Nothing)
    

    这是 n 维列表的三参数版本:

    {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
    
    class Select bs as where
      select :: bs -> as -> as -> as
    
    instance Select Bool a where
      select True x _ = x
      select False _ y = y
    
    instance (Select bs as) => Select [bs] [as] where
      select = zipWith3 select
    

    这是一个例子:

    GHCi> select [[True, False], [False, True]] [[0,1],[2,3]] [[4,5],[6,7]]
    [[0,5],[6,3]]
    

    不过,您可能希望在实践中使用适当的 n 维数组类型。如果您只想在一个特定的 n 的 n 维列表上使用 select,则 luqui 的建议(来自此答案的 cmets)更可取:

    在实践中,我会使用(zipWith3.zipWith3.zipWith3) select' bs xs ys(对于三维情况)而不是 typeclass hack。

    (随着 n 的增加,添加更多 zipWith3 的组合。)

    【讨论】:

    • 在实践中,我会使用(zipWith3.zipWith3.zipWith3) select' bs xs ys(对于三维情况)而不是 typeclass hack。如果我在写的时候不知道维数,那么,如你所说,我会使用合适的抽象类型。
    • 是的,我完全同意。不过,如果你真的想在 Haskell 中实现numpy.where...谢谢你让我知道zipWith3 可以在这里工作,顺便说一句!我已经相应地编辑了我的答案,并包含了您的评论。 :)
    【解决方案2】:

    来自numpy.where.__doc__的python:

    If `x` and `y` are given and input arrays are 1-D, `where` is
    equivalent to::
    
        [xv if c else yv for (c,xv,yv) in zip(condition,x,y)]
    

    【讨论】:

      【解决方案3】:

      where 有两个用例;在一种情况下,您有两个数组,而在另一种情况下,您只有一个。

      在两个项目的情况下,numpy.where(cond),您将获得条件数组为真的索引列表。在 Scala 中,您通常会

      (cond, cond.indices).zipped.filter((c,_) => c)._2
      

      这显然不太紧凑,但这不是人们通常在 Scala 中使用的基本操作(例如,构建块不同,不强调索引)。

      在三项情况下,numpy.where(cond,x,y),您会得到 xy,具体取决于 cond 是真 (x) 还是假 (y)。在 Scala 中,

      (cond, x, y).zipped.map((c,tx,ty) => if (c) tx else ty)
      

      执行相同的操作(同样不那么紧凑,但通常不是基本操作)。请注意,在 Scala 中,您可以更轻松地让 cond 成为测试 xy 并产生真假的方法,然后您就可以

      (x, y).zipped.map((tx,ty) => if (c(tx,ty)) tx else ty)
      

      (尽管通常即使很简短,您也会将数组命名为 xsys 以及单个元素 xy)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-13
        • 1970-01-01
        • 1970-01-01
        • 2019-10-14
        • 2019-05-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多