1. ホーム
  2. r

[解決済み】自作関数を書くときにRの省略機能を使うには?

2022-04-13 17:56:12

質問

R言語には、可変数の引数を取ることができる関数を定義するための気の利いた機能があります。例えば、関数 data.frame は任意の数の引数を取り、各引数は結果のデータテーブルの1列のデータとなる。使用例。

> data.frame(letters=c("a", "b", "c"), numbers=c(1,2,3), notes=c("do", "re", "mi"))
  letters numbers notes
1       a       1    do
2       b       2    re
3       c       3    mi

関数のシグネチャには、次のように省略記号が含まれています。

function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, 
    stringsAsFactors = default.stringsAsFactors()) 
{
    [FUNCTION DEFINITION HERE]
}

複数の値を受け取り、それらを1つの戻り値に統合する(他の処理も行う)、似たようなことを行う関数を書きたいと思います。これを実現するために、私は、quot;unpack" をどのように行うかを理解する必要があります。 ... を関数内の引数から削除してください。どうすればいいのかわからない。関数の定義の中で、関連する行 data.frameobject <- as.list(substitute(list(...)))[-1L] というのは、全く意味がわからない。

では、関数のシグネチャにある省略記号を、たとえばリストに変換するにはどうすればよいのでしょうか?

具体的には、どのように書けばよいのでしょうか。 get_list_from_ellipsis を以下のコードに追加してください。

my_ellipsis_function(...) {
    input_list <- get_list_from_ellipsis(...)
    output_list <- lapply(X=input_list, FUN=do_something_interesting)
    return(output_list)
}

my_ellipsis_function(a=1:10,b=11:20,c=21:30)


編集

2つの方法が考えられるようです。それは as.list(substitute(list(...)))[-1L]list(...) . しかし、この2つは全く同じことをするわけではありません。(違いについては、回答の例をご覧ください。) どなたか、この2つの実用的な違い、そしてどちらを使うべきかを教えていただけませんか?

どのように解決するのですか?

回答やコメントを読んでいると、いくつか言及されていないことがあるようです。

  1. data.frame 用途 list(...) バージョンになります。コードの断片。

    object <- as.list(substitute(list(...)))[-1L]
    mrn <- is.null(row.names)
    x <- list(...)
    
    

    object はカラム名に魔法をかけるために使われますが x は、最終的な data.frame .

    評価されない ... 引数は write.csv コード match.call が使用されます。

  2. Dirk answerのコメント結果に書かれているように、リストのリストではありません。長さ4のリストで、要素は次のとおりです。 language タイプになります。最初のオブジェクトは symbol - list であり、2つ目は式 1:10 といった具合です。そのため、なぜ [-1L] が必要です:これは、期待される symbol で提供された引数から ... (常にリストであるため)。

    Dirkが言うように substitute は "評価されていない式をパースツリー化する" を返します。

    を呼び出すと my_ellipsis_function(a=1:10,b=11:20,c=21:30) では ... "create"引数のリストを作成します。 list(a=1:10,b=11:20,c=21:30)substitute は、4つの要素からなるリストになります。

    List of 4
    $  : symbol list
    $ a: language 1:10
    $ b: language 11:20
    $ c: language 21:30
    
    

    最初の要素には名前がなく、これは [[1]] をDirkの回答で紹介しました。私はこの結果を使用して達成します。

    my_ellipsis_function <- function(...) {
      input_list <- as.list(substitute(list(...)))
      str(input_list)
      NULL
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
    
    
  3. 上記のように str を使用して、関数にどのようなオブジェクトが含まれているかを確認します。

    my_ellipsis_function <- function(...) {
        input_list <- list(...)
        output_list <- lapply(X=input_list, function(x) {str(x);summary(x)})
        return(output_list)
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
     int [1:10] 1 2 3 4 5 6 7 8 9 10
     int [1:10] 11 12 13 14 15 16 17 18 19 20
     int [1:10] 21 22 23 24 25 26 27 28 29 30
    $a
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       1.00    3.25    5.50    5.50    7.75   10.00 
    $b
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       11.0    13.2    15.5    15.5    17.8    20.0 
    $c
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       21.0    23.2    25.5    25.5    27.8    30.0 
    
    

    大丈夫です。見てみましょう。 substitute のバージョンです。

       my_ellipsis_function <- function(...) {
           input_list <- as.list(substitute(list(...)))
           output_list <- lapply(X=input_list, function(x) {str(x);summary(x)})
           return(output_list)
       }
       my_ellipsis_function(a=1:10,b=11:20,c=21:30)
        symbol list
        language 1:10
        language 11:20
        language 21:30
       [[1]]
       Length  Class   Mode 
            1   name   name 
       $a
       Length  Class   Mode 
            3   call   call 
       $b
       Length  Class   Mode 
            3   call   call 
       $c
       Length  Class   Mode 
            3   call   call 
    
    

    私たちが必要としているものではありません。この種のオブジェクトを扱うには、追加のトリックが必要になります(たとえば write.csv ).

を使用したい場合は ... であれば、シェーンの回答のように list(...) .