Rで1行に複数の変数を代入したいのですが、このようなことは可能でしょうか?
values # initialize some vector of values
(a, b) = values[c(2,4)] # assign a and b to values at 2 and 4 indices of 'values'
通常、複数行ではなく、1 行で約 5 ~ 6 個の変数を割り当てたいと考えています。代替手段はありますか?
Rで1行に複数の変数を代入したいのですが、このようなことは可能でしょうか?
values # initialize some vector of values
(a, b) = values[c(2,4)] # assign a and b to values at 2 and 4 indices of 'values'
通常、複数行ではなく、1 行で約 5 ~ 6 個の変数を割り当てたいと考えています。代替手段はありますか?
Struggling Through Problems ブログに素晴らしい回答があります。
これは、非常に小さな変更を加えたものです。
次の 3 つの関数の使用 (さらに、異なるサイズのリストを許可するための 1 つ)
# Generic form
'%=%' = function(l, r, ...) UseMethod('%=%')
# Binary Operator
'%=%.lbunch' = function(l, r, ...) {
Envir = as.environment(-1)
if (length(r) > length(l))
warning("RHS has more args than LHS. Only first", length(l), "used.")
if (length(l) > length(r)) {
warning("LHS has more args than RHS. RHS will be repeated.")
r <- extendToMatch(r, l)
}
for (II in 1:length(l)) {
do.call('<-', list(l[[II]], r[[II]]), envir=Envir)
}
}
# Used if LHS is larger than RHS
extendToMatch <- function(source, destin) {
s <- length(source)
d <- length(destin)
# Assume that destin is a length when it is a single number and source is not
if(d==1 && s>1 && !is.null(as.numeric(destin)))
d <- destin
dif <- d - s
if (dif > 0) {
source <- rep(source, ceiling(d/s))[1:d]
}
return (source)
}
# Grouping the left hand side
g = function(...) {
List = as.list(substitute(list(...)))[-1L]
class(List) = 'lbunch'
return(List)
}
新しい関数を使用して左辺をグループ化しますg()
右辺はベクトルまたはリストである必要があります新しく作成された二項演算子を使用します%=%
# Example Call; Note the use of g() AND `%=%`
# Right-hand side can be a list or vector
g(a, b, c) %=% list("hello", 123, list("apples, oranges"))
g(d, e, f) %=% 101:103
# Results:
> a
[1] "hello"
> b
[1] 123
> c
[[1]]
[1] "apples, oranges"
> d
[1] 101
> e
[1] 102
> f
[1] 103
左側が長い
g(x, y, z) %=% list("first", "second")
# Warning message:
# In `%=%.lbunch`(g(x, y, z), list("first", "second")) :
# LHS has more args than RHS. RHS will be repeated.
> x
[1] "first"
> y
[1] "second"
> z
[1] "first"
右側が長い
g(j, k) %=% list("first", "second", "third")
# Warning message:
# In `%=%.lbunch`(g(j, k), list("first", "second", "third")) :
# RHS has more args than LHS. Only first2used.
> j
[1] "first"
> k
[1] "second"
たとえば、1行のデータフレーム(たとえばV
)を作成し、その中で変数を初期化します。これで、一度に複数の変数に割り当てたりV[,c("a", "b")] <- values[c(2, 4)]
、それぞれを名前で呼び出す(V$a
)、またはそれらの多くを同時に使用する()ことができvalues[c(5, 6)] <- V[,c("a", "b")]
ます。
怠惰になり、データフレームから変数を呼び出したくない場合は、可能ですattach(V)
(私は個人的にはそうしませんが)。
# Initialize values
values <- 1:100
# V for variables
V <- data.frame(a=NA, b=NA, c=NA, d=NA, e=NA)
# Assign elements from a vector
V[, c("a", "b", "e")] = values[c(2,4, 8)]
# Also other class
V[, "d"] <- "R"
# Use your variables
V$a
V$b
V$c # OOps, NA
V$d
V$e
これが私の考えです。おそらく構文は非常に単純です。
`%tin%` <- function(x, y) {
mapply(assign, as.character(substitute(x)[-1]), y,
MoreArgs = list(envir = parent.frame()))
invisible()
}
c(a, b) %tin% c(1, 2)
このように与えます:
> a
Error: object 'a' not found
> b
Error: object 'b' not found
> c(a, b) %tin% c(1, 2)
> a
[1] 1
> b
[1] 2
ただし、これは十分にテストされていません。
潜在的に危険な (使用assign
が危険である限り) オプションは次のようになりますVectorize
assign
。
assignVec <- Vectorize("assign",c("x","value"))
#.GlobalEnv is probably not what one wants in general; see below.
assignVec(c('a','b'),c(0,4),envir = .GlobalEnv)
a b
0 4
> b
[1] 4
> a
[1] 0
mapply
または、おそらく引数に適切なデフォルトを使用して、独自の関数を使用して手動でベクトル化できると思いますenvir
。たとえば、Vectorize
は と同じ環境プロパティ (assign
この場合は) を持つ関数を返します。namespace:base
または、単に を設定することもできますenvir = parent.env(environment(assignVec))
。
他の人が説明したように、何も組み込まれていないようです。 ...しかしvassign
、次のように関数を設計できます。
vassign <- function(..., values, envir=parent.frame()) {
vars <- as.character(substitute(...()))
values <- rep(values, length.out=length(vars))
for(i in seq_along(vars)) {
assign(vars[[i]], values[[i]], envir)
}
}
# Then test it
vals <- 11:14
vassign(aa,bb,cc,dd, values=vals)
cc # 13
ただし、考慮すべきことの 1 つは、たとえば 3 つの変数と 5 つの値を指定する場合、またはその逆の場合の処理方法です。ここでは、変数と同じ長さになるように値を繰り返す (または切り捨てる) だけです。たぶん、警告は賢明でしょう。ただし、次のことが可能です。
vassign(aa,bb,cc,dd, values=0)
cc # 0
list2env(setNames(as.list(rep(2,5)), letters[1:5]), .GlobalEnv)
つまり、最初の 5 文字に 5 つの 2 を割り当てました。
https://stat.ethz.ch/R-manual/R-devel/library/base/html/list2env.html :
list2env(
list(
a=1,
b=2:4,
c=rpois(10,10),
d=gl(3,4,LETTERS[9:11])
),
envir=.GlobalEnv
)
1 行のコードのみが必要な場合は、次のようにします。
> a<-values[2]; b<-values[4]
残念ながら、あなたが探している(のようなc(a, b) = c(2, 4)
)エレガントなソリューションは残念ながら存在しません。でもあきらめないでください、よくわかりません!私が考えることができる最も近い解決策はこれです:
attach(data.frame(a = 2, b = 4))
または、警告が気になる場合は、それらをオフにします。
attach(data.frame(a = 2, b = 4), warn = F)
しかし、あなたはこの解決策に満足していないと思いますが、私もそうではありません...
再帰を伴う別のバージョン:
let <- function(..., env = parent.frame()) {
f <- function(x, ..., i = 1) {
if(is.null(substitute(...))){
if(length(x) == 1)
x <- rep(x, i - 1);
stopifnot(length(x) == i - 1)
return(x);
}
val <- f(..., i = i + 1);
assign(deparse(substitute(x)), val[[i]], env = env);
return(val)
}
f(...)
}
例:
> let(a, b, 4:10)
[1] 4 5 6 7 8 9 10
> a
[1] 4
> b
[1] 5
> let(c, d, e, f, c(4, 3, 2, 1))
[1] 4 3 2 1
> c
[1] 4
> f
[1] 1
私のバージョン:
let <- function(x, value) {
mapply(
assign,
as.character(substitute(x)[-1]),
value,
MoreArgs = list(envir = parent.frame()))
invisible()
}
例:
> let(c(x, y), 1:2 + 3)
> x
[1] 4
> y
[1]