web-dev-qa-db-ja.com

dplyrの標準評価:文字列として与えられた変数を要約します

summarise内の不明な列名を参照したい。 _dplyr 0.3_で導入された標準の評価関数では、変数を使用して列名を参照できますが、これは、たとえばbase R関数を呼び出したときに機能しないようです。 summarise

_library(dplyr)

key <- "v3"
val <- "v2"
drp <- "v1"

df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))
_

Dfは次のようになります。

_> df
Source: local data frame [5 x 3]

  v1 v2 v3
1  1  6  A
2  2  7  A
3  3  8  A
4  4  9  B
5  5 10  B
_

V1をドロップし、v3でグループ化し、各グループのv2を合計します。

_df %>% select(-matches(drp)) %>% group_by_(key) %>% summarise_(sum(val, na.rm = TRUE))

Error in sum(val, na.rm = TRUE) : invalid 'type' (character) of argument
_

select()のNSEバージョンは、文字列と一致できるため、正常に機能します。 group_by()のSEバージョンは、変数を引数として受け入れて評価できるようになったため、正常に動作します。ただし、dplyr関数内でベースR関数を使用する場合、同様の結果を達成する方法は見つかりませんでした。

動作しないもの:

_df %>% group_by_(key) %>% summarise_(sum(get(val), na.rm = TRUE))
Error in get(val) : object 'v2' not found

df %>% group_by_(key) %>% summarise_(sum(eval(as.symbol(val)), na.rm = TRUE))
Error in eval(expr, envir, enclos) : object 'v2' not found
_

複数関連質問 をチェックアウトしましたが、これまでのところ提案された解決策はどれもうまくいきませんでした。

46
Ajar

Rlangパッケージのリリースとdplyrの0.7.0アップデートにより、これはかなり簡単になりました。

文字列(「v1」など)を変数名として使用する場合、次のようにします。

  1. Rlangパッケージのsym()を使用して、文字列をシンボルに変換します
  2. 関数呼び出しで、シンボルの前に_!!_を記述します

たとえば、次のことを行います。

_my_var <- "Sepal.Length"
my_sym <- sym(my_var)
summarize(iris, Mean = mean(!!my_sym))
_

よりコンパクトにするには、関数呼び出しを記述するときに、sym()を使用して文字列をシンボルに変換し、_!!_をプレフィックスとして追加するステップを組み合わせることができます。

たとえば、次のように書くことができます。

_my_var <- "Sepal.Length"
summarize(iris, mean(!!sym(my_var)))
_


元の例に戻るには、次のことができます。

_library(rlang)

key <- "v3"
val <- "v2"
drp <- "v1"

df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))

df %>% 
  # NOTE: we don't have to do anything to `drp`
  # since the matches() function expects a character string
  select(-matches(drp)) %>% 
  group_by(!!sym(key)) %>% 
  summarise(sum(!!sym(val), na.rm = TRUE))
_


代替構文

Rlangバージョン0.4.0のリリースでは、次の構文を使用できます。

_my_var <- "Sepal.Length"
my_sym <- sym(my_var)
summarize(iris, Mean = mean({{ my_sym }}))
_

_!!my_sym_を書く代わりに、_{{ my_sym }}_を書くことができます。これには間違いなく明確であるという利点がありますが、括弧内に文字列を配置する前に文字列を記号に変換する必要があるという欠点があります。たとえば、!!sym(my_var)と書くことはできますが、できない{{sym(my_var)}}と書くことはできません

追加の詳細

sym()と_!!_の使用方法を説明する公式ドキュメントの中で、これらは最もアクセスしやすいようです:

  1. dplyr vignette:dplyrを使用したプログラミング

  2. メタプログラミングに関するHadley Wickhamの著書「Advanced R」のセクション

26
bschneidr

この回答は、notは_dplyr >= 0.7.0_に適用されますが、以前のバージョンには適用されることに注意してください。

[_dplyr 0.7.0_] には、tidyevalと呼ばれる非標準評価(NSE)への新しいアプローチがあります。 vignette("programming")で詳細に説明されています。


ここでは dplyr非標準評価のビネット が役立ちます。 「定数と変数の混合」セクションを確認すると、パッケージinterpの関数lazyevalを使用できることがわかります。文字列がある場合は、[[u] se _as.name_変数名を与える」:

_library(lazyeval)
df %>%
  select(-matches(drp)) %>%
  group_by_(key) %>%
  summarise_(sum_val = interp(~sum(var, na.rm = TRUE), var = as.name(val)))
#   v3 sum_val
# 1  A      21
# 2  B      19
_
53
Henrik

.dots引数に、pastesprintfを使用して、またはlistの代わりにfn$listを介してパッケージgsubfnから文字列補間を使用して、文字列を構成する文字列のリストを渡します。ここで行います:

library(gsubfn)
df %>% 
   group_by_(key) %>% 
   summarise_(.dots = fn$list(mean = "mean($val)", sd = "sd($val)"))

与える:

Source: local data frame [2 x 3]

  v3 mean        sd
1  A  7.0 1.0000000
2  B  9.5 0.7071068
9
G. Grothendieck

新しいdplyrの更新:

これには、dplyrの新しい機能が役立ちます。非標準の評価を必要とする変数の文字列の代わりに、Quosures quo()を使用します。別の関数!!で引用を取り消します。これらの詳細については このビネットを参照 。完全なリリースまで dplyrの開発者バージョン が必要です。

library(dplyr) #0.5.0.9004+
key <- quo(v3)
val <- quo(v2)
drp <- "v1"

df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))
df %>% select(-matches("v1")) %>% 
  group_by(!!key) %>% 
  summarise(sum(!!val, na.rm = TRUE))
# # A tibble: 2 × 2
#      v3 `sum(v2, na.rm = TRUE)`
#   <chr>                   <int>
# 1     A                      21
# 2     B                      19
9