关于R、Python、VBA、SAS的生成批量变量名与动态变量引用的问题

1. 什么是动态变量?

i=1
x&i=3

x&i就是动态变量。

如果x&i按照我们所想的一样,那么上述程序的结果应该是得到了一个变量x1=3

上述程序在VBA中可直接实现。

动态变量可以用于批量变量迭代,这是动态变量最重要的意义。如:

for(i in 1:100){
x&i=i
}

这是时候我们快速地生成了x1:x100这100个变量,并进行了赋值。如果x&i的作用按照我们想的一样实现了的话,那么上述程序应该生成了x1=1,x2=x,x3=3...x100=100

所以问题的核心就是x&i的实现,核心的核心就是&的含义。

在SAS中,我记得连接需要加一个英文句号:

x&.i=3

在VBA中,可直接用

x&i=3

然而在R与Python要复杂得多。

2. Python中动态变量的实现:locals()函数

i=1
locals()['x'+str(i)]=3

上面已经讲了,动态变量的实现关键在于&符号的实现。在Python中,& 并不表示连接,也不表示逻辑。Python中的逻辑运算符是and or not。上面的i是可以迭代的,因此这个问题就得到了完美的解决。

3. R中动态变量的引用

我最爱的R在这里确实最复杂的,&在R中是逻辑运算“和”,并不表示连接。

一般有五种方法能够实现变量批量命名:

  • 对list使用setName
my_power_list=setNames( as.list( 1:5), paste0("x", 1:5) )

效果是这样的:

关于R、Python、VBA、SAS的生成批量变量名与动态变量引用的问题

这实际上用了一个列名重命名技术而已。而且只在列表中,效果很有限。

  • list2env转换全局变量
x =as.list(rnorm(100))
names(x) = paste("a", 1:100, sep = "")#列表重命名
list2env(x , envir = .GlobalEnv)#将列表变量转换为全局变量

关于R、Python、VBA、SAS的生成批量变量名与动态变量引用的问题

  • eval(paste)解析法
vals <- rnorm(3)
n    <- length(vals)
lhs  <- paste("a",    1:n,     sep="")
rhs  <- paste("vals[",1:n,"]", sep="")
eq   <- paste(paste(lhs, rhs, sep="<-"), collapse=";")
eval(parse(text=eq))

其本质是生成了一段文本,然后用parse去解析,在用eval进行符号运算。

上面的三种并不是很常用,我比较喜欢下面两种:

  • assign(paste)
assign(paste0("x", 1:100), 1:100)

这一次性生成了100个变量:xi=i。

上面已经讲到,动态变量最重要的意义是能够利用迭代对变量进行批量运算。很遗憾,仅仅凭借上面的函数是无法实现迭代的。我们需要另外一个函数:get()。get函数和assign是一对,assign给字符赋值,get获得字符的值。

现在看一个实例。假定有一个数据集d是100行30列的,也就是说有30个变量,现在用bootstrap收集它的系数。进行100次随机抽样,每一次抽样用第一列数据对其他列进行线性回归,这样,每一次回归都会得到一次beta0~beta29,一共30个beta(还有个截距项beta0)。进行100次抽样后再回归就得到了100个不同的beta0,把这些beta0全部追加到变量beta0中。然后进行统计量的估计。也就是说,最后我们的结果是:关于R、Python、VBA、SAS的生成批量变量名与动态变量引用的问题

d=matrix(rnorm(100*30),100,30)
d=data.frame(d)
cs=paste0('beta',1:30)
for(k in 1:30){
  assign(cs[k],c())
}#要追加必给初值
for(j in 1:100){
  i=sample(1:100,80,replace = F)
  d1=d[i,]
  model=lm(X1~.,data=d1)
  for(k in 1:30){
    assign(cs[k],c(get(cs[k]),coef(model)[k]))
  }
}

关于R、Python、VBA、SAS的生成批量变量名与动态变量引用的问题

如果不进行动态变量引用,那么我们程序可能是这样滴:

d=matrix(rnorm(100*30),100,30)
d=data.frame(d)
beta0=c()
beta1=c()
beta2=c()
beta3=c()
beta4=c()
beta5=c()
beta6=c()
beta7=c()
...
beta30=c()
for(j in 1:100){
  i=sample(1:100,80,replace = F)
  d1=d[i,]
  model=lm(X1~.,data=d1)
  beta0=c(beta0,coef(model)[1])
  beta1=c(beta1,coef(model)[2])
  beta2=c(beta2,coef(model)[3])
  beta3=c(beta3,coef(model)[4])
  beta4=c(beta4,coef(model)[5])
  beta5=c(beta5,coef(model)[6])
  beta6=c(beta6,coef(model)[7])
  beta7=c(beta7,coef(model)[8])
  ...
  beta30=...
}

现在你知道了动态引用的重要意义了吧,没错,几十倍地精简代码!对变量进行批量迭代!

再看最后一种方法。

  • globalen进行动态引用

这种方法其实是最符合x&i定义的一种方法。

e=globalenv()
name=paste0('x',1:5)
e[[name[1]]]=3

似乎有点像Python的locals,但是注意:

  1. 必须使用一个变量指代globalen(),即关于R、Python、VBA、SAS的生成批量变量名与动态变量引用的问题,而Python中可以直接使用locals()
  2. 必须有一个变量,里面包含了要全局化的变量名,这和assign(paste)也一样,也需要有全部的变量名
  3. e后面必须是双括号

使用这种方法进行bootstrap:

e=globalenv()
cs=paste0('beta',1:30)
for(k in 1:30){
  assign(cs[k],c())
}

for(j in 1:100){
  i=sample(1:100,80,replace = F)
  d1=d[i,]
  model=lm(X1~.,data=d1)
  for(k in 1:30){
    e[[cs[k]]]=c(e[[cs[k]]],coef(model)[k])
  }
}