本サイトは広告・プロモーションが含まれています
Python

【困り事メモ】numpy.fromfunction を理解する【Numpy】

どうもこんにちは。
コンです。

数あるNumpyライブラリの関数の一つである
numpy.fromfunction

画像処理で使われる、ガウシアンフィルタであったり
配列の処理に非常に役に立つ関数ですので、この関数の使い方を具体例をだしながら
解説したいと思います。

基本

まずはNumpyの公式ページに紹介されているのがこんな感じです。

○numpy.fromfunction(function(必須), shape(必須), *dtype=<class ‘float’>like=None, **kwargs)
○retrun : from functionany : any

これをちょっとずつ解説させていただくと
○function:関数、なんでもよい。公式はlambda(無名関数)を使ってますが定義した関数でも大丈夫です
○shape:outputの行列の形、functionによるんですけど、例えば(2, 2)にするとoutputがarray([[0, 0], [1, 1]]) もしくは array([[0, 1], [0, 1]])になるらしい。
○dtypeとlike:オプション
○**kwargs : **アスタリスクを2つで可変長の辞書型、とりあえず色々変数いれるよ〜って意味です。

引用:https://numpy.org/doc/stable/reference/generated/numpy.fromfunction.html

でこんな感じの例なんですが、よくわからなかったので色々試してみてました。

まずは lambdaについて

lambdaは無名関数と呼ばれるもので、その名前の通り名前のない関数です。
以下のような形式で記述します。

lambda 引数 : 返り値

例えば次のように使用することができます。

lambda_fn = lambda n: n * 3
print(lambda_fn(4))
###12と出力されます

実際のlambdaコードを動かす部分はこちらのページでも紹介しているので、是非読んでみてください。

shapeってなんだ?

公式を読んでいてわからなかったのが、shapeについてでした。
これは、基本1次元なら[0, 1, 2, 3, …], 2次元なら([[0, 0], [1, 1]])が 出力されるそうです。

1次元

data = np.fromfunction(lambda x:x, (10, ), dtype=float)
print(data)
#[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]と出力される

def f(x):
  return x*2
data2 = np.fromfunction(f, (10, ), dtype=float)
print(z data2)
#data2, [ 0.  2.  4.  6.  8. 10. 12. 14. 16. 18.]と出力される

なんとなくshapeの形にfor文で1づつ増えていき、関数によって返り値が変化する
といった結果になりました。

2次元

次に2次元について書いていきます。

こちらは計算とかlambdaとかを含むとややこしいので、基本的に
入力変数をそのまま出力する関数を使い、np.fromfunctionがどんな計算をするのか
みていきましょう。

def g(x, y):
  return x
data3 = np.fromfunction(g, (5, 5), dtype=float)
print('data3', data3, len(data3))
'''
[0. 0. 0. 0. 0.]
 [1. 1. 1. 1. 1.]
 [2. 2. 2. 2. 2.]
 [3. 3. 3. 3. 3.]
 [4. 4. 4. 4. 4.]], 5 と表示される
'''

def j(x, y):
  return x, y
data4 = np.fromfunction(j, (5, 5), dtype=float)
print('data4', data4, len(data4))
'''
(array([[0., 0., 0., 0., 0.],
       [1., 1., 1., 1., 1.],
       [2., 2., 2., 2., 2.],
       [3., 3., 3., 3., 3.],
       [4., 4., 4., 4., 4.]]), array([[0., 1., 2., 3., 4.],
       [0., 1., 2., 3., 4.],
       [0., 1., 2., 3., 4.],
       [0., 1., 2., 3., 4.],
       [0., 1., 2., 3., 4.]])) 2と表示される
'''

def k(x, y):
  return x+y, x-y

data5 = np.fromfunction(k, (5, 5), dtype=float)
print('data5', data5, len(data5))

'''
array([[0., 1., 2., 3., 4.],
       [1., 2., 3., 4., 5.],
       [2., 3., 4., 5., 6.],
       [3., 4., 5., 6., 7.],
       [4., 5., 6., 7., 8.]]), array([[ 0., -1., -2., -3., -4.],
       [ 1.,  0., -1., -2., -3.],
       [ 2.,  1.,  0., -1., -2.],
       [ 3.,  2.,  1.,  0., -1.],
       [ 4.,  3.,  2.,  1.,  0.]])) 2と表示される
'''

1つめの(5×5)配列は行が増えるごとに1づつ増えていき、2つ目の(5×5)配列は列が増えるごとに数字が増えていきます。

関数を足し算、引き算に変更した時の結果もよくわかると思います。

この結果を知っていると、公式ページが出している以下の例も
わかりやすいですよね。
1つ目が上のコードのdata3、4つ目がdata5の最初の配列のreturnを示しています。

引用:https://numpy.org/doc/stable/reference/generated/numpy.fromfunction.html

3次元

3次元も、これまたややこしいので3×3の配列で
入力の値をそのまま出力してみます。

これまた難しいとはおもいますが
1つ目の(3×3)配列は奥行き方向が増えるごとに(3×3)行列の全ての要素1ずつ増えていき、あとは2次元どうように2つ目・3つ目の配列は行・列が増えるごとに数字が増えていきます。

こう書いてみると、かなり分かりやすくなったと思います。

おわりに

ここまで読んでいただき、誠にありがとうございます。
Pythonを7年もやっているのに、知らないことだらけなんだなと最近は実感するばかりです。

他にもこんな面白い関数あるよ。
なんてのがあったら是非教えてください。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA