備忘ログ

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

match.arg()を使うと選択肢を受け取る引数の省略時既定値からうまく選んで入れてくれる

Rのmatch.arg()について挙動については

統計言語 R 探訪 match.arg() 編 - ほくそ笑む

がすごくよくまとまっているので、これを読むべき。


今回は上のブログ記事でまとめられている挙動とは違う挙動が気になった件について。

基本的な挙動なのかもしれないけれど、自学自習なので、ちゃんとメモしておく。


きっかけは、学生協で本を購入すると本体価格から10%値引きされて購入できるのですが計算としては(本体価格-本体価格10%)(1+消費税)となっており、本体価格からだと計算も簡単なのですが税込価格(要するにAmazonでの表示価格)しかわからないと一回本体価格を計算してから計算しなければいけない。

「この本ほしいなぁ」と思ったときに、Amazon見て値段見て学生協で買ったときの価格知りたいけどAmazonの表示価格は税込価格なのでめんどくさいのでRで自作関数を作って計算することに。

本体価格でも計算できるようにしたり、値引率や消費税率を変えて計算できるようにした自作関数が、

# 学生協で本を買ったときの値段を計算する
# kakakuは"amazon"が税込価格、"hontai"が本体価格で計算
# discountは学生協での本体価格からの値引率
# taxは消費税率

seikyou.kakaku <- function(x, 
                           kakaku = c("amazon", "hontai"),
                           discount = 10,
                           tax = 10){
  if(kakaku == "amazon"){
    x <- x/(1 + tax * 0.01)
  }
 (x - (x * discount * 0.01 )) * (1 + tax * 0.01)
}

で、実行するとちゃんと計算してくれるのだがkakakuの引数を毎回選ぶのがめんどくさい、というか基本的にはAmazon見て計算するのでしたくないが、本体価格からも計算したいときもあるので選択肢の設定を落としたくない(わがまま)

一応kakakuの引数を指定しないでも計算できるが、実行すると

seikyou.kakaku(3000)
[1] 2700
 警告メッセージ: 
 if (kakaku == "amazon") {: 
   条件が長さが 2 以上なので、最初の 1 つだけが使われます  

とエラーがでてきて、たまにしか使わないなら気にならないけどときどき使う(予定)だし、今後欲しいものリストをスクレイピングして値段の計算するかもしれないのでエラーが出続けるのは気持ち悪い。

そういえばt.test()だと、alternativeが選択式の引数になっているが選ばなくても引数の選択肢のリストの一番最初two.sidedを選んでくれるのはなぜだろうと思ってソースを調べると、match.arg()を使っている模様だということを初めて知る。(alternativeの引数をいじっている関数がmatch.arg()しかなかったから。)

んで修正した自作関数が

seikyou.kakaku <- function(x, 
                           kakaku = c("amazon", "hontai"),
                           discount = 10,
                           tax = 10){
  kakaku <- match.arg(kakaku)
  if(kakaku == "amazon"){
    x <- x/(1 + tax * 0.01)
  }
  (x - (x * discount * 0.01 )) * (1 + tax * 0.01)
}

で実行するとデフォルトで税込価格から計算してくれて、エラーも出なくなる。

で、いろいろ調べてみて最初に上げたブログを読んでみたけど、省略時既定値の引数設定については触れられていなかった。 (でも、期待された文字列の最初数文字でもちゃんと動く理由がわかってよかった。)

なぜに選択肢の引数の省略時既定値がちゃんと選択肢リストの一番最初のものを入力してくれるのかソースを見てみると、

function (arg, choices, several.ok = FALSE) 
{
 (以下略)
    if (!several.ok) {
        if (identical(arg, choices)) 
            return(arg[1L])
(以下略)
}

となっている箇所が該当箇所だと思う。

several.okの既定値がFALSEになっているので、特に選択していないとif(!several.ok)がTRUEになって、それまでの流れでarg(自作関数ではkakakuの選択肢として設定しているものがまるっと投入されているはず)とchoices(自作関数ではkakakuの選択肢と設定されているものがなにかが投入されているはず)は同じになる(なぜそうなるかは一番上にあげたブログ参照)ので、引数の選択肢項目の一番最初がreturnで返されて終了するとのこと。

これにより、選択肢の既定値が入力しなくてもエラーを出さずに計算してくれることになるので便利。

自作関数が捗る。