1. ホーム
  2. r

[解決済み] 変数名が文字ベクトルで格納されている場合のdata.tableへの選択と代入

2023-01-12 23:20:27

質問

の中でどのように変数を参照するのですか? data.table の中で、変数名が文字ベクトルに格納されている場合、どのように参照するのでしょうか?例えば、これは data.frame :

df <- data.frame(col1 = 1:3)
colname <- "col1"
df[colname] <- 4:6
df
#   col1
# 1    4
# 2    5
# 3    6

これと同じ操作をdata.tableに対して行うにはどうしたらよいでしょうか。 := の記法の有無にかかわらず、data.table に対して同じ操作を行うにはどうしたらよいでしょうか。明らかなのは dt[ , list(colname)] は機能しません(期待もしていませんでした)。

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

プログラムによる2つの方法 を選択する 変数を選択する方法です。

  1. with = FALSE :

     DT = data.table(col1 = 1:3)
     colname = "col1"
     DT[, colname, with = FALSE] 
     #    col1
     # 1:    1
     # 2:    2
     # 3:    3
    
    
  2. 'ドットドット' ( .. ) の接頭辞があります。

     DT[, ..colname]    
     #    col1
     # 1:    1
     # 2:    2
     # 3:    3
    
    

ドットドット」のさらなる記述については、( .. ) 記法については 1.10.2での新機能 を参照してください (現在、ヘルプテキストでは説明されていません)。

への を割り当てる のLHSを変数に代入します。 := を括弧で囲む。

DT[, (colname) := 4:6]    
#    col1
# 1:    4
# 2:    5
# 3:    6

後者はカラムと呼ばれる ポンポン と呼ばれ、列ベクトル全体を参照で置き換えるからです。もしサブセット i が存在すれば、それは参照によってサブアサインされます。 を囲む括弧は (colname) は、2014年10月CRAN上のバージョンv1.9.4で導入された略記法です。以下は は、ニュース項目 :

<ブロッククオート

使用方法 with = FALSE:= を包むことは、すべての場合において非推奨となりました。 のLHSを := のLHSを括弧で囲むことが以前から好まれていたことを考えると、すべてのケースで非推奨となります。

<ブロッククオート
colVar = "col1"

DT[, (colVar) := 1]                             # please change to this
DT[, c("col1", "col2") := 1]                    # no change
DT[, 2:4 := 1]                                  # no change
DT[, c("col1","col2") := list(sum(a), mean(b))]  # no change
DT[, `:=`(...), by = ...]                       # no change

参照 詳細 セクションの ?`:=` :

DT[i, (colnamevector) := value]
# [...] The parens are enough to stop the LHS being a symbol


そして、コメントでのさらなる質問に答えるために、ここに一つの方法があります(いつものように、多くの方法があります):

DT[, colname := cumsum(get(colname)), with = FALSE]
#    col1
# 1:    4
# 2:    9
# 3:   15 

にしておけば、読み書きやデバッグが楽になるかもしれません。 eval a paste というように、サーバーに送信する動的な SQL 文を作成するのと同じです。

expr = paste0("DT[,",colname,":=cumsum(",colname,")]")
expr
# [1] "DT[,col1:=cumsum(col1)]"

eval(parse(text=expr))
#    col1
# 1:    4
# 2:   13
# 3:   28

もし、そのようなことを頻繁に行うのであれば、ヘルパー関数として EVAL :

EVAL = function(...)eval(parse(text=paste0(...)),envir=parent.frame(2))

EVAL("DT[,",colname,":=cumsum(",colname,")]")
#    col1
# 1:    4
# 2:   17
# 3:   45

では、その data.table 1.8.2 は自動的に j を効率よく使うように最適化します。 eval メソッドを使うのが望ましいかもしれません。この場合 get()j は、例えばいくつかの最適化を阻止します。

あるいは、そこに set() . 低オーバーヘッドで機能的な形式である := という形で、ここでは問題ないでしょう。参照 ?set .

set(DT, j = colname, value = cumsum(DT[[colname]]))
DT
#    col1
# 1:    4
# 2:   21
# 3:   66