关于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) )
效果是这样的:
这实际上用了一个列名重命名技术而已。而且只在列表中,效果很有限。
- list2env转换全局变量
x =as.list(rnorm(100))
names(x) = paste("a", 1:100, sep = "")#列表重命名
list2env(x , envir = .GlobalEnv)#将列表变量转换为全局变量
- 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中。然后进行统计量的估计。也就是说,最后我们的结果是:。
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]))
}
}
如果不进行动态变量引用,那么我们程序可能是这样滴:
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,但是注意:
- 必须使用一个变量指代globalen(),即
,而Python中可以直接使用locals()
- 必须有一个变量,里面包含了要全局化的变量名,这和assign(paste)也一样,也需要有全部的变量名
- 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])
}
}