1. 導入編

はじめに

  • lambdaR は、R にラムダ式を導入するためのパッケージ
  • 関数型プログラミングを行うパッケージとしてpurrrがある
  • {base}では、関数プログラミング用6つの高階関数を備えている
    • MapReduceFilterNegateFindPosition
  • {lambdaR}では、高階関数を改造してパイプライクにしている



登録数

## [1] 12
##  [1] "f_"        "Filter_"   "Find_"     "lambda"    "Map_"     
##  [6] "Map2_"     "Map2v_"    "Mapu_"     "Mapv_"     "Negate_"  
## [11] "Position_" "Reduce_"



2. 高階関数とラムダ式

高階関数

  • 引数に関数オブジェクトを持つことができる関数群のこと
    • {base}ではMapReduceFilterNegateFindPositionがある
    • apply関数ファミリーも高階関数の1つ
  • データセットに対して高階関数の処理引数で与えた関数の処理を融合して行う
  • 高階関数を使うことで、apply関数ファミリー以外の処理を行うことが可能


ラムダ式

  • ラムダ式とは、無名関数の生成を簡単にする方法
  • {lambdaR}では関数定義にまつわる冗長性を取り除いてくれる
# 1変数のラムダ式
lambda(x: x + 1) %>% print()
## function (x) 
## x + 1
# 2変数のラムダ式
lambda(x,y: x + y) %>% print()
## function (x, y) 
## x + y




3. 記法の比較

高階関数をそのまま使う

  • {base}でも関数型プログラミング用に高階関数が用意されている
  • 引数の1番目がデータではないのでパイプライクではない
# 変数宣言が多い
# データセットの位置が第2引数なのでパイプライクではない
data <-1:10
fil <- Filter(function(x){x %% 2 == 0}, data) %T>% print()
## [1]  2  4  6  8 10
map <- Map(function(x){x ** 2}, fil) %T>% list.tree()
##  . = list 5 (328 bytes)
## .  [[1]] = double 1= 4
## .  [[2]] = double 1= 16
## .  [[3]] = double 1= 36
## .  [[4]] = double 1= 64
## .  [[5]] = double 1= 100
res <- Reduce(function(x, y){x + y}, map) %T>% list.tree()
##  . = double 1 (48 bytes)= 220
res %>% print()
## [1] 220


高階関数をパイプ化する

  • パイプライクな引数構造ではないが、パイプ化はできる
# やはりデータセットを落とす落ちが遠い
# --- "."を使って指定しなければならない
1:10 %>% 
  Filter(function(x){x %% 2 == 0}, .) %>% 
  Map(function(x){x ** 2}, .) %>% 
  Reduce(function(x, y){x + y}, .) %>% 
  print()
## [1] 220


{lambdaR}の高階関数を使う

  • 高階関数の引数にfunction()を書かなくてよいのでスッキリ
# データセットの位置が最初なのでパイプライク
# "function"の宣言が必要なくなった
1:10 %>% 
  Filter_(x: x %% 2 == 0) %>% 
  Map_(x: x ** 2) %>% 
  Reduce_(x, y: x + y) %>% 
  print()
## [1] 220


{lambdaR}のプレースフォルダを使う

# 変数宣言までも省略できる
1:10 %>% 
  Filter_(._ %% 2 == 0) %>% 
  Map_(._ ** 2) %>% 
  Reduce_(._ + ._) %>% 
  print()
## [1] 220




4. 関数研究

Map

  • 引数にベクトルリストを与えて、個別に処理をしていく
    • 並行処理のイメージ
  • 処理はリスト形式で行われて、結果もリスト形式で返される
# 通常の高階関数
1:3 %>% Map(function(x){x + 2}, .) %>% list.tree()
##  . = list 3 (216 bytes)
## .  [[1]] = double 1= 3
## .  [[2]] = double 1= 4
## .  [[3]] = double 1= 5
# Map関数の{lambdaR}版
1:3 %>% Map_(x: x + 2) %>% list.tree()
##  . = list 3 (216 bytes)
## .  [[1]] = double 1= 3
## .  [[2]] = double 1= 4
## .  [[3]] = double 1= 5
# 結果をベクトルで返すこともできる
# --- Map Vector / Map unlist
1:3 %>% Mapv_(x: x + 2)
## [1] 3 4 5
1:3 %>% Mapu_(x: x + 2)
## [1] 3 4 5
# 複数のデータセットを代入する
list(1:3, 11:13) %>% Map2_(x, y: x + y) %>% list.tree()
##  . = list 3 (216 bytes)
## .  [[1]] = integer 1= 12
## .  [[2]] = integer 1= 14
## .  [[3]] = integer 1= 16
# 結果をベクトルで返すこともできる
list(1:3, 11:13) %>% Map2v_(x, y: x + y)
## [1] 12 14 16



Reduce

  • 引数にベクトルリストを与えて、前から逐次的に処理をしていく
    • 累積処理のイメージ
    • 引数に初期値も指定できる
  • 処理はリスト形式で行われて、結果もリスト形式で返される
# 通常の高階関数
1:10 %>% Reduce(function(x, y){x + y}, .)
## [1] 55
# 途中プロセスを見ることもできる
1:10 %>% Reduce(function(x, y){x + y}, ., accumulate = TRUE)
##  [1]  1  3  6 10 15 21 28 36 45 55
# Reduce関数の{lambdaR}版
1:10 %>% Reduce_(x, y: x + y)
## [1] 55
# こちらも途中プロセスを見ることもできる
1:10 %>% Reduce_(x, y: x + y, accumulate = TRUE)
##  [1]  1  3  6 10 15 21 28 36 45 55


(参考)Reduce関数の動作イメージ

# 直前の計算値を逐次的に使って累積してく
interest <- c(1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 
              1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 1.05, 1.05)
Reduce(function(a, b){a * b},init = 100, interest, accumulate = T)
##  [1] 100.0000 105.0000 110.2500 115.7625 121.5506 127.6282 134.0096
##  [8] 140.7100 147.7455 155.1328 162.8895 171.0339 179.5856 188.5649
## [15] 197.9932 207.8928 218.2875 229.2018 240.6619 252.6950 265.3298



Filter

  • 条件を与えて、一致した要素のみを取り出す
    • Negate()Finter()を組み合わせると逆の操作も可能
  • 処理はベクトル形式で行われて、結果もベクトル形式で返される
# 通常の高階関数
1:10 %>% Filter(function(x){x %% 2 == 0}, .)
## [1]  2  4  6  8 10
# Filter関数の{lambdaR}版 
1:10 %>% Filter_(x: x %% 2 == 0)
## [1]  2  4  6  8 10



Negate

  • 条件を与えて、一致しない要素を取得する
    • Filterと併せて使うことで、Filterと逆の操作(偽の取得)を行うことができる
    • 同様のことはFilter()の条件変更(from == to <>)でも可能
  • 処理はベクトル形式で行われて、結果もベクトル形式で返される
# 通常の高階関数 (調整中) 
1:10 %>% Filter(Negate(function(x){x %% 2 == 0}), .)
## [1] 1 3 5 7 9
# Filterの逆処理
1:10 %>% Filter_(Negate_(x: x %% 2 == 0))
## [1] 1 3 5 7 9



Find

  • 条件を与えて、一致した要素のみを取り出す
    • Negate()は逆の操作を行う
  • 処理はベクトル形式で行われて、結果もベクトル形式で返される
# 通常の高階関数
LETTERS  %>% Find(function(x) {tolower(x) == "f"}, .)
## [1] "F"
# Filter関数の{lambdaR}版 
LETTERS %>% Find_(x: tolower(x) == "f")
## [1] "F"


(参考) 関数紹介

# 大文字を小文字に変換する
tolower("A")
## [1] "a"



Position

  • 条件を与えて、一致した要素のみを取り出す
    • Negate()は逆の操作を行う
  • 処理はベクトル形式で行われて、結果もベクトル形式で返される
# 通常の高階関数
LETTERS  %>% Position(function(x) {x == "F"}, .)
## [1] 6
# Filter関数の{lambdaR}版 
LETTERS %>% Position_(x: x == "F")
## [1] 6
inserted by FC2 system