web-dev-qa-db-ja.com

numpyの行列の行/列に対する関数の適用

Numpyを使用してデータを行列に格納しています。 Rバックグラウンドから来て、行列の行/列または両方に関数を適用する非常に簡単な方法がありました。

Python/numpyの組み合わせに似たものがありますか?私自身の小さな実装を書くことは問題ではありませんが、私が思いつくバージョンのほとんどは、既存の実装のどれよりも非常に効率が悪く、メモリをより多く消費するでしょう。

Numpy行列からローカル変数などにコピーすることを避けたいのですが、それは可能ですか?

私が実装しようとしている関数は、主に単純な比較です(たとえば、特定の列の要素の数がxより小さいか、yより大きい絶対値を持つ要素の数)。

36
petr

ほぼすべてのnumpy関数は配列全体で動作し、特定の軸(行または列)で動作するように指示できます。

Numpy配列または配列スライスに作用するnumpy関数に関して関数を定義できる限り、関数は配列、行、または列全体で自動的に動作します。

より具体的なアドバイスを得るために、特定の関数を実装する方法について尋ねると、より役立つ場合があります。


Numpyは、 np.vectorize および np.frompyfunc を提供し、Python numpy配列を操作する関数に数値を操作する関数を提供します。

例えば、

def myfunc(a,b):
    if (a>b): return a
    else: return b
vecfunc = np.vectorize(myfunc)
result=vecfunc([[1,2,3],[5,6,9]],[7,4,5])
print(result)
# [[7 4 5]
#  [7 6 9]]

(2番目の配列が大きい場合、最初の配列の要素は2番目の配列の対応する要素に置き換えられます。)

しかし、興奮しすぎないでください。 np.vectorizeおよびnp.frompyfunc are 単なる構文糖 。実際には、コードが速くなるわけではありません。基になるPython関数が一度に1つの値で動作している場合、np.vectorizeは一度に1つのアイテムをフィードし、操作全体がかなり遅くなります(基礎となるCまたはFortran実装を呼び出すnumpy関数の使用と比較して)。


xの数がyより小さい要素の数を数えるには、次のような式を使用できます。

(array['x']<y).sum()

例えば:

import numpy as np
array=np.arange(6).view([('x',np.int),('y',np.int)])
print(array)
# [(0, 1) (2, 3) (4, 5)]

print(array['x'])
# [0 2 4]

print(array['x']<3)
# [ True  True False]

print((array['x']<3).sum())
# 2
43
unutbu

1つ以上の条件に基づいてNumPy配列から要素を選択するのは、NumPyの美しく緻密な構文を使用して簡単です。

>>> import numpy as NP
>>> # generate a matrix to demo the code
>>> A = NP.random.randint(0, 10, 40).reshape(8, 5)
>>> A
  array([[6, 7, 6, 4, 8],
         [7, 3, 7, 9, 9],
         [4, 2, 5, 9, 8],
         [3, 8, 2, 6, 3],
         [2, 1, 8, 0, 0],
         [8, 3, 9, 4, 8],
         [3, 3, 9, 8, 4],
         [5, 4, 8, 3, 0]])


列2の要素が6より大きいか?

>>> ndx = A[:,1] > 6
>>> ndx
      array([False,  True, False, False,  True,  True,  True,  True], dtype=bool)
>>> NP.sum(ndx)
      5


Aの最後の列の絶対値が3より大きい要素はいくつですか?

>>> A = NP.random.randint(-4, 4, 40).reshape(8, 5)
>>> A
  array([[-4, -1,  2,  0,  3],
         [-4, -1, -1, -1,  1],
         [-1, -2,  2, -2,  3],
         [ 1, -4, -1,  0,  0],
         [-4,  3, -3,  3, -1],
         [ 3,  0, -4, -1, -3],
         [ 3, -4,  0, -3, -2],
         [ 3, -4, -4, -4,  1]])

>>> ndx = NP.abs(A[:,-1]) > 3
>>> NP.sum(ndx)
      0


Aの最初の2行の要素が2以上である要素の数は?

>>> ndx = A[:2,:] >= 2
>>> NP.sum(ndx.ravel())    # 'ravel' just flattens ndx, which is originally 2D (2x5)
      2

NumPyのインデックス構文はRに非常に近いです。 Rの流encyさを考えると、このコンテキストでのRとNumPyの主な違いは次のとおりです。

NumPy インデックスはゼロベースです、Rでは、インデックスは1から始まります

NumPy(Pythonと同様)を使用すると、負のインデックスを使用してインデックスを右から左にできます。

# to get the last column in A
A[:, -1], 

# to get the penultimate column in A
A[:, -2] 

# this is a big deal, because in R, the equivalent expresson is:
A[, dim(A)[0]-2]

NumPyはcolon ":"表記を使用して "unsliced"を示します。たとえば、Rでは、最初の3行を取得しますA、A [1:3、]を使用します。 NumPyでは、A [0:2、:]を使用します(NumPyでは、「0」は必要ありません。実際、A [:2、:]を使用することをお勧めします

14
doug

また、私はより多くのRのバックグラウンドから来ており、カスタマイズされた短い機能を取ることができる、より汎用性の高い適用の欠如にぶつかりました。それらの多くが配列を処理するため、基本的なnumpy関数の使用を提案するフォーラムを見てきました。ただし、「ネイティブな」numpy関数が配列を処理する方法について混乱しています(0が行方向、1が列方向、時にはその逆)。

Apply_along_axisを使用したより柔軟な関数への私の個人的な解決策は、Pythonで利用可能な暗黙的なラムダ関数とそれらを結合することでした。 Lambda関数は、R関数apply、sapply、lapplyなど、より機能的なプログラミングスタイルを使用するR志向の人にとって非常に理解しやすいものでなければなりません。

したがって、たとえば、マトリックス内の変数の標準化を適用したかったのです。通常、Rにはこのための関数(スケール)がありますが、applyを使用して簡単に構築することもできます。

(Rコード)

apply(Mat,2,function(x) (x-mean(x))/sd(x) ) 

Apply(x-mean(x))/ sd(x)内の関数の本体が、python apply_along_axis。lambdaでこれを直接入力できないビットです。 FOR ONE SET OF VALUESを簡単に実装できます。

(Python)

import numpy as np
vec=np.random.randint(1,10,10)  # some random data vector of integers

(lambda x: (x-np.mean(x))/np.std(x)  )(vec)

次に、これをpython applyにプラグインし、apply_along_axisを通じて目的の配列を渡すだけです。

Mat=np.random.randint(1,10,3*4).reshape((3,4))  # some random data vector
np.apply_along_axis(lambda x: (x-np.mean(x))/np.std(x),0,Mat )

明らかに、ラムダ関数は別の関数として実装できますが、全体のポイントは、適用が発生した行に含まれるかなり小さな関数を使用することだと思います。

それがあなたの役に立つことを願っています!

7
markcelo

Pandas は非常に便利です。たとえば、 DataFrame.apply() および groupby's apply() が役立ちます。

3
Peter Battaglia