2017-12-05 10 views
1

dplyrのリニューアル版では、filter_などの関数のアンダースコアバージョンは、tidy evaluationになります。dplyr tidyevalに相当するアンダースコア関数のバージョン

新しい方法で期待される新しいアンダースコアフォームはどんなものですか? R CMDチェックで未定義シンボルを回避する方法を書いていますか?

library(dplyr) 

df <- data_frame(id = rep(c("a","b"), 3), val = 1:6) 
df %>% filter_(~id == "a") 

# want to avoid this, because it references column id in a variable-style 
df %>% filter(id == "a") 

# option A 
df %>% filter(UQ(rlang::sym("id")) == "a") 
# option B 
df %>% filter(UQ(as.name("id")) == "a") 
# option C 
df %>% filter(.data$id == "a") 

優先フォームがありますか?オプションCは最短ですが、私の現実世界の大規模なデータセットと、より複雑なdplyr構築物の一部に遅い:

microbenchmark(
sym = dsPClosest %>% 
    group_by(!!sym(dateVarName), !!sym("depth")) %>% 
    summarise(temperature = mean(!!sym("temperature"), na.rm = TRUE) 
      , moisture = mean(!!sym("moisture"), na.rm = TRUE)) %>% 
    ungroup() 
,data = dsPClosest %>% 
    group_by(!!sym(dateVarName), .data$depth) %>% 
    summarise(temperature = mean(.data$temperature , na.rm = TRUE) 
       , moisture = mean(.data$moisture , na.rm = TRUE)) %>% 
    ungroup() 
,times=10 
) 
#Unit: milliseconds 
# expr  min   lq  mean  median  uq  max neval 
# sym 80.05512 84.97267 122.7513 94.79805 100.9679 392.1375 10 
# data 4652.83104 4741.99165 5371.5448 5039.63307 5471.9261 7926.7648 10 

answer for mutate_は、さらに複雑な構文を使用してあります。

+1

私は 'utils :: globalVariables()'を使用して、dplyr式で使用しているすべての変数名を登録します。 – lionel

+0

seplyrパッケージを見てください。 –

答えて

1

あなたのコメントに基づいて、私はそれは次のようになり推測:あなたは!!as.nameの代わりに、UQsymでこれを行うことができますよう

df %>% filter(!!as.name("id") == "a") 

rlangは、不要です。

しかし、おそらくより良いオプションはquosure関連の問題を回避スコープフィルター、次のとおりです。vars()上記のコードで

df %>% filter_at(vars("id"), all_vars(. == "a")) 

は、どの列我々は助けに(フィルタリング文を適用しようとしていると判断しますfilter_atの場合、フィルタステートメントは「述語」と呼ばれ、この場合、列にのみ適用されます。all_vars()またはany_vars()のいずれかのステートメントになります。 all_vars(. == "a")は、のすべての列は"a"と等しくなければなりません。はい、少し混乱します。あなたの例と同様のデータのための

タイミング:この場合、我々はgroup_by_atsummarise_atを使用し、それらの機能のバージョンスコープされています

set.seed(2) 
df <- data_frame(group = sample(1:100,1e4*52,replace=TRUE), 
       id = rep(c(letters,LETTERS), 1e4), 
       val = sample(1:50,1e4*52,replace=TRUE)) 

microbenchmark(
quosure=df %>% group_by(!!as.name("group"), !!as.name("id")) %>% 
    summarise(val = mean(!!as.name("val"))), 
data=df %>% group_by(.data$group, .data$id) %>% 
    summarise(val = mean(.data$val)), 
scoped_group_by = df %>% group_by_at(vars("group","id")) %>% 
    summarise_at("val", mean), times=10) 
Unit: milliseconds 
      expr  min  lq  mean median  uq  max neval cld 
     quosure 59.29157 61.03928 64.39405 62.60126 67.93810 72.47615 10 a 
      data 391.22784 394.65636 419.24201 413.74683 425.11709 498.42660 10 b 
scoped_group_by 69.57573 71.21068 78.26388 76.67216 82.89914 91.45061 10 a 

オリジナル回答

これは、あなたが裸のnとしてフィルタ変数を入力する場合です次に、enquo!!UQに相当)を使用して、filter変数を使用します。たとえば、次のように

library(dplyr) 

fnc = function(data, filter_var, filter_value) { 
    filter_var=enquo(filter_var) 
    data %>% filter(!!filter_var == filter_value) 
} 

fnc(df, id, "a") 
 id val 
1  a  1 
2  a  3 
3  a  5 
fnc(mtcars, carb, 3) 
mpg cyl disp hp drat wt qsec vs am gear carb 
1 16.4 8 275.8 180 3.07 4.07 17.4 0 0 3 3 
2 17.3 8 275.8 180 3.07 3.73 17.6 0 0 3 3 
3 15.2 8 275.8 180 3.07 3.78 18.0 0 0 3 3 
それでも
+0

ありがとう@ eipi10しかし、これは別の問題であるようです。私はパラメータを渡すのではなく、簡潔な構文で、(一見グローバルな)記号の代わりに文字列または式として固定列名を指定する方法に興味があります。ありがとう@ eipi10。 –

+0

あなたの更新された答えは、あなたが使用しない限り、オプションBに似ています。 UQの代わりに。フィルターを使用すると、私はUQを使用する必要がありました。私のフィルターの設定では!!オプションが機能しませんでした。 –

+0

'filter_at'を使いすぎる2番目の解決策があまりにも好きではありません。なぜなら、実際には何を読むのは難しいからです。 –

0
# option D: uses formula instead of string 
df %>% filter(UQ(f_rhs(~id)) == "a") 

非常に冗長が、二重引用符を回避することができます。

マイクロベンチマークは、オプションBよりも速い(つまり、スモールティック)、つまりas.nameソリューションです。

0
# option F: using the dot . 
df %>% filter(.$id == "a") 

# slow in progtw's real-world problem: 
microbenchmark(
    sym = dsPClosest %>% 
    group_by(!!sym(dateVarName), !!sym("depth")) %>% 
    summarise(temperature = mean(!!sym("temperature"), na.rm = TRUE) 
       , moisture = mean(!!sym("moisture"), na.rm = TRUE)) %>% 
    ungroup() 
    ,dot = dsPClosest %>% 
    group_by(!!sym(dateVarName), .$depth) %>% 
    summarise(temperature = mean(.$temperature , na.rm = TRUE) 
       , moisture = mean(.$moisture , na.rm = TRUE)) %>% 
    ungroup() 
    ,times=10 
) 
#Unit: milliseconds 
# expr   min   lq   mean  median   uq   max neval 
# sym  75.37921  78.86365  90.72871  81.22674  90.77943 163.2081 10 
# dot 115452.88945 116260.32703 128314.44451 125162.46876 136578.09888 149193.9751 10 

オプションc(.data $)に似ていますが、それより短いです。しかし、私の実際のアプリケーションではパフォーマンスが低下していました。

また、これをいつ使用できるかについてのドキュメントは見つかりませんでした。

関連する問題