9

非標準評価は、dplyr の動詞を使用する場合に非常に便利です。しかし、関数の引数でこれらの動詞を使用すると問題が発生する可能性があります。たとえば、特定の種の行数を取得する関数を作成したいとします。

# Load packages and prepare data
library(dplyr)
library(lazyeval)
# I prefer lowercase column names
names(iris) <- tolower(names(iris))
# Number of rows for all species
nrow(iris)
# [1] 150

例が機能しない

species この関数は、関数の引数のコンテキストではなく、アイリス データ フレームのコンテキストで解釈されるため、期待どおりに動作しません。

nrowspecies0 <- function(dtf, species){
    dtf %>%
        filter(species == species) %>%
        nrow()
}
nrowspecies0(iris, species = "versicolor")
# [1] 150

3つの実装例

非標準の評価を回避するために、通常は引数にアンダースコアを追加します。

nrowspecies1 <- function(dtf, species_){
    dtf %>%
        filter(species == species_) %>%
        nrow()
}

nrowspecies1(iris, species_ = "versicolor")
# [1] 50
# Because of function name completion the argument
# species works too
nrowspecies1(iris, species = "versicolor")
# [1] 50

関数の引数の名前を使いにくい名前に変更するため、完全に満足できるものではありません。または、オートコンプリートに依存していますが、これはプログラミングの良い習慣ではありません。素敵な引数名を保持するには、次のようにします。

nrowspecies2 <- function(dtf, species){
    species_ <- species
    dtf %>%
        filter(species == species_) %>%
        nrow()
}
nrowspecies2(iris, species = "versicolor")
# [1] 50

この回答に基づいて非標準評価を回避する別の方法。 関数環境のコンテキストでinterp()解釈します。species

nrowspecies3 <- function(dtf, species){
    dtf %>%
        filter_(interp(~species == with_species, 
                       with_species = species)) %>%
        nrow()
}
nrowspecies3(iris, species = "versicolor")
# [1] 50

上記の 3 つの関数を考慮して、このフィルター関数を実装するための推奨される (最も堅牢な) 方法は何ですか? 他の方法はありますか?

4

3 に答える 3

1

Hadley Wickham は2016 年の UserR talk (@38min30s) で、参照透過性の概念について説明しています。式を使用すると、フィルター関数は次のように再定式化できます。

nrowspecies5 <- function(dtf, formula){
    dtf %>%
        filter_(formula) %>%
        nrow()
}

これには、より一般的であるという追加の利点があります

# Make column names lower case
names(iris) = tolower(names(iris)) 
nrowspecies5(iris, ~ species == "versicolor")
# 50
nrowspecies5(iris, ~ sepal.length > 6 & species == "virginica")
# 41
nrowspecies5(iris, ~ sepal.length > 6 & species == "setosa")
# 0
于 2016-08-11T13:56:41.543 に答える