どのように "どこ"(numpy.where(...))を実装するのですか?

私は機能プログラミング初心者です。 私は、python、scala、またはhaskellでnumpy.where()を実装する方法を知りたいと思います。 良い説明が私に役立つだろう。

2

3 答え

Haskellでは、NumPyの等価物がサポートしているように、n次元のリストを作成するためにはかなり高度なtypeclass構​​造が必要ですが、1次元の場合は簡単です:

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のドキュメントの定義を翻訳している、1次元のリストのための簡単ではあるがあまり明白でない実装があります(それを指摘するためのjoaquinへのクレジット)。

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

2つの引数の場合(条件が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次元リストの3つの引数バージョンがあります:

{-# 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次元配列型を使用することをお勧めします。 1つの特定の n に対してn次元のリストで select を使用する場合は、luquiのアドバイス(この回答のコメントから)を参考にしてください。

実際には、typeclassのハックではなく、(zipWith3.zipWith3.zipWith3)を選択して(3次元の場合) 'bs xs ys

zipWith3 の構成を n として追加すると増加します)。

6
追加された
はい、私は完全に。それでも、Haskellで numpy.where を実装したいのであれば、ここでは zipWith3 を使っていただきありがとうございます!私はそれに応じて私の答えを編集し、あなたのコメントが含まれています。 :)
追加された 著者 ehird,
"完全に同意する"と "私は実現する"もちろん、:)
追加された 著者 ehird,
実際には、typeclassのハックの代わりに、(zipWith3.zipWith3.zipWith3)を選択して、 'bs xs ys (3次元の場合)を選択します。私が書いているときに次元の数がわからないなら、あなたが言ったように、私は適切な抽象型を使用します。
追加された 著者 luqui,

Pythonの numpy.where .__ doc __ から:

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)]
5
追加された

ここでは2つのユースケースがあります。 1つのケースでは、2つの配列を持ち、もう1つの配列しか持っていません。

2項目の場合、 numpy.where(cond)では、条件配列が真であるインデックスのリストを取得します。 Scalaでは、通常は

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

明らかにそれほどコンパクトではありませんが、これは人がScalaで通常使用する基本的な操作ではありません(ビルディングブロックは異なる、たとえば強調しないインデックスなど)。

numpy.where(cond、x、y)の3項目の場合、 x y > がtrue( x )またはfalse( y )であることを確認します。 Scalaでは、

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

同じ動作を行う(コンパクト性は低下するが、やはり通常は基本的な動作ではない)。 Scalaでは、 x y をテストして真または偽を生成するメソッドとして、 cond

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

(典型的には簡潔であっても、配列 xs ys と個々の要素 x y )。

3
追加された