備忘ログ

チラシの裏的備忘録&メモ

Rで畳み込み(線形畳み込み)を行うconvolve()関数のメモなど

ちょっとしたメモ、三本立て。

Rで畳み込み(線形畳み込み)を行うconvolve()関数のメモ

Rでベクトルの畳み込みを行うconvolve()関数のメモ({stats}パッケージの関数で通常ではRの起動時にロードされている)。

線形畳み込み(普通の畳み込み)を行うときには引数のtypetype = "open"とする。既定値ではtype = "circular"で循環畳み込みになっている。

このとき、xyをそれぞれ計算するベクトルとしたとき、pythonnumpyを用いた場合のnumpy.convolve(x, y)とすると、同じような結果をRのconvolve()関数で得ようとすると2つ目のベクトルを逆順にして与える必要がある。つまり、convolve(x, rev(y), type = "open")とする必要がある。ヘルプドキュメント読むとちゃんとかいてる。

実行例

x <- 1:3
y <- 4:6
convolve(x, rev(y), type = "open")
## [1]  4 13 28 27 18

convolve()関数のヘルプドキュメントを読むと

Arguments

x, y numeric sequences of the same length to be convolved.

と書いてあるが、線形畳み込みの場合は2つのベクトルの長さが同じである必要はない。

y <- 4:7
convolve(x, rev(y), type = "open")
## [1]  4 13 28 34 32 21

循環畳み込みの場合には、当然2つのベクトルの長さが同じである必要がある。ヘルプドキュメントを読むと一瞬混乱する。

雑感

上記の通り、引数のヘルプドキュメントをみると線形畳み込みでも同じ長さのベクトルしか計算できないのか?と少し混乱する(多分だが、誰ももこのヘルプドキュメントを読んでいないんじゃないかと思う)。

また、関数名がconvolvenumpyと一緒だが、Rでは既定値でtype = "circular"となっており循環畳み込みになっていること、通常の線形畳み込みをするためには2つ目に与えるベクトルをrev()関数で順番を逆にしなければならないのが気をつけなければならない点となる。

ちゃんとヘルプドキュメントを読んでないとrev()しないとnumpyの結果と一致しないことに混乱するし、ちゃんとヘルプドキュメントを読んだら読んだで線形畳み込みでもベクトルの長さ異なったらだめなの?と混乱する謎の展開。

ja.wikipedia.org

二項演算子とパイプのメモ

二項演算子とパイプ演算子の注意のメモ。

単純な例で考える。たとえば、2つのベクトルc(1, 2)c(3, 4)の積をとってそのベクトルの和をとる場合を考える。

sum(1:2 * 3:4)
## [1] 11

これで計算できる。このとき、1:2 * 3:4を計算してから|>%>%などのパイプをつかって、sum()に計算結果を渡して和を計算しようと考えた時に、次のようなコードを書くと意図した通りには計算できない。

1:2 * 3:4 |> sum()
## [1]  7 14
library(magrittr)
1:2 * 3:4 %>% sum()
## [1]  7 14

これは、3:4が先にsum()に渡されて、1:2 * sum(3:4)が実行されてしまうため。{lobstr}パッケージのast()関数をつかって確認してみる。

lobstr::ast(1:2 * 3:4 |> sum())
## █─`*` 
## ├─█─`:` 
## │ ├─1 
## │ └─2 
## └─█─sum 
##   └─█─`:` 
##     ├─3 
##     └─4
lobstr::ast(1:2 * 3:4 %>% sum())
## █─`*` 
## ├─█─`:` 
## │ ├─1 
## │ └─2 
## └─█─`%>%` 
##   ├─█─`:` 
##   │ ├─3 
##   │ └─4 
##   └─█─sum

つまり、

`*`(1:2, 3:4 |> sum())
## [1]  7 14
`*`(1:2, 3:4 %>% sum())
## [1]  7 14

という処理になっている。関数でカッコでくくられるとわかりやすい。

一応、{lobstr}ast()で確認してみる。

lobstr::ast(`*`(1:2, 3:4 |> sum()))
## █─`*` 
## ├─█─`:` 
## │ ├─1 
## │ └─2 
## └─█─sum 
##   └─█─`:` 
##     ├─3 
##     └─4
lobstr::ast(`*`(1:2, 3:4 %>% sum()))
## █─`*` 
## ├─█─`:` 
## │ ├─1 
## │ └─2 
## └─█─`%>%` 
##   ├─█─`:` 
##   │ ├─3 
##   │ └─4 
##   └─█─sum

この場合、パイプで繋ぐのをそのものやめるか(こっちのほうがいいと思う)、パイプを使いたかったら先に1:2 * 3:4を計算すればいいのでカッコでくくってやればいい。

(1:2 * 3:4) |> sum()
## [1] 11
(1:2 * 3:4)  %>%  sum()
## [1] 11

これくらい単純だとわかりやすく踏み抜きにくいと思うが、少し複雑になると注意が必要と思う。

{naniar}パッケージはナルニア国物語

{naniar}パッケージのアップデートが降ってきたときにNEWSを読んでいると変わったときどきのリリースに変わったコードネームが書かれていることに気付いた。

たとえば、0.5.0は“The End of this Story and the Beginning of all of the Others”で、なんだこの長いコードネーム?厨二病か?と思ってコードネームでググったらナルニア国物語のChapterや主要なイベントや人名(?)だとわかった。他のコードネームもナルニア国物語関連だった。

で、{naniar}のREADMEを読んだらA note on the nameの項でナルニア国物語にもじっていることが書いてあった。おしゃれー、と思った。

naniar.njtierney.com