查看原文
其他

数据科学03 | R语言程序设计-给符号赋值

联川生物 2022-05-21

The following article is from 珠江肿瘤 Author 李雪纯 冯文清

R赋值规则

例:定义了名为lm的函数,使用lm符号时,赋值新定义的lm函数还是stats包中拟合线性模型的lm函数?

lm<-function(x){x * x}lmfunction(x){x * x}

给符号赋值时,R将在一系列的环境中进行搜索在从而找到合适的值。

搜索列表顺序:

search()[1] ".GlobalEnv" "tools:rstudio" "package:stats" "package:graphics" [5] "package:grDevices" "package:utils" "package:datasets" "package:methods" [9] "Autoloads" "package:base"
  1. 全局环境(工作区)

  2. 当前载入 R 的所有 R 包的命名空间

  3. base 包在搜索列表的最后一位

1.每加载一个包,这个包的命名空间会排在搜索列表的第二位,其它包向后移一位。2.函数和非函数在 R 中有不同的命名空间,存在一个名为c的向量与名为c的函数不冲突,但全局环境中只能有一个名为c的符号。

library(stringr)search() [1] ".GlobalEnv" "package:stringr" "tools:rstudio" [4] "package:stats" "package:graphics" "package:grDevices" [7] "package:utils" "package:datasets" "package:methods" [10] "Autoloads" "package:base"
mean <- 1:10mean(mean)[1] 5.5mean[1] 1 2 3 4 5 6 7 8 9 10

名为mean的向量和已有的函数mean()不冲突,但全局环境中只有一个名为mean的符号,给符号mean赋值时,首先在全局环境中找到的是名为mean的向量。

R 的作用域规则

➢函数的变量类型

形式参数,通过函数定义传入函数;

自由变量,存在于函数中的非参数的变量或符号。

f <- function(x, y) {  x^2+y/z}

x、y是形式参数;符号 z 是自由变量。一个语言的作用域规则决定了如何给自由变量赋值。

词法作用域(静态作用域)lexical scoping:R语言动态作用域dynamic scoping:其他编程语言

➢词法作用域规则:

在定义函数的环境中搜索自由变量的值。

环境是符号值对的集合。环境可能有一个父环境(上层环境)和多个子环境。空环境没有父环境。  

  • 一般而言,一个函数会在定义它的环境中查找自由变量的值,再到它的父环境中查找,继续在父环境的父环境中查找,以此类推,直到找到自由变量的值或到达顶层环境

  • 通常顶层环境就是全局环境;如果函数在包中定义,那么顶层环境是那个包的命名空间,搜索到达顶层环境后,会沿着搜索列表继续进行直到到达空环境

  • 如果到达空环境仍未查找到相应的自由变量符号,就会报错,错误信息是无法为这个符号找到对应的值 

定义全局变量可以在工作区里定义的不同函数中通用。

在 R 中关键不同在于,构造性函数能在函数里面构造另一个函数。被构造的目标函数的环境就不是全局环境,而是在构造性函数内部。

例: 

make.power <- function(n) { pow <- function(x) { x^n } pow }

自由变量n不是在 pow() 内部定义,而是在 make.power() 内部定义,make.power() 内部也是定义 pow() 的环境,因此pow() 能在这个环境中找到n的值。

cube <- make.power(3) #调用make.power()返回函数cubesquare <- make.power(2) #调用make.power()返回函数squarecube(3)[1] 27square(3)[1] 9

ls ()函数查看定义这个函数的环境。

ls(environment(cube))[1] "n" "pow"get("n", environment(cube)) #在cube函数内部查找自由变量n的值[1] 3
ls(environment(square))[1] "n" "pow"get("n", environment(square))[1] 2

➢比较词法作用域和动态作用域

y <- 10f <- function(x){ y <- 2 y^2+g(x)}g <- function(x){ x*y}f(3)34
在f()函数中y和g()都是自由变量,在g()函数中y也是自由变量,g()中的y取值为?
词法作用域:g() 中 y 的值是在定义这个函数的环境即全局环境中查到的,所以函数 g() 中 y 取值为10。
动态作用域:y 的值要考虑调用这个函数的调用环境 (calling environment),调用环境里的 y 等于2,所以 g() 中 y 取值为2。 

在全局环境中定义函数,并在全局环境中调用该函数,这样定义环境和调用环境就是同一个环境。 

g <- function(x) { a<-3 x+a+y}g(2)Error in g(2) : 找不到对象'y'#x是形式参数;a是局部变量,a不是形式参数但在函数中定义;y是自由变量,g()会在全局环境中寻找y的值
y<-3g(2)[1] 8#定义y等于3,g(2)就能在全局环境中找到y

词法作用域要求所有对象都必须保存在内存里。

优化 (optimization)

➢处理优化问题的基本思想

利用构造函数构造一个目标函数,把目标函数所依赖的所有参数、数据等都整合在目标函数的定义环境中,每次调用函数时不必特意说明,只需要声明参数的值。代码不需要加上很长的参数列表,更简洁。

➢词法作用域应用:优化

R 中自带优化函数optim(),nlm() 和 optimize()默认求目标函数的最小值。优化函数调整目标函数的参数来实现函数的最小化。要实现目标函数的最大化,先取它的负值再把它进行最小化。 

例:构造一个负的对数似然函数 (log likelihood),对这个负的对数似然函数进行最小化。

  1. 定义构造函数make.NegLogLik()构造目标函数——负的对数似然函数

make.NegLogLik <- function(data, fixed=c(FALSE,FALSE)) { params <- fixed function(p) { params[!fixed] <- p mu <- params[1] sigma <- params[2] a <- -0.5*length(data)*log(2*pi*sigma^2) b <- -0.5*sum((data-mu)^2) / (sigma^2) -(a+b) }}

・make.NegLogLik() 函数的第一个参数data是目标函数依赖的数据;・第二个参数fixed是一个逻辑向量,决定是否要固定目标函数的某些参数;・构造函数内部定义了目标函数,目标函数的参数是p(需要调整优化的参数向量);・构造函数返回正态分布(mu,sigma)的负的对数似然函数。

  1. 调用构造函数make.NegLogLik()返回目标函数nLL()

#模拟随机变量数据,服从正态分布(1,2)set.seed(1); normals <- rnorm(100, 1, 2)#对随机变量数据调用构造函数,构造目标函数nLL()nLL <- make.NegLogLik(normals)nLLfunction(p) { params[!fixed] <- p mu <- params[1] sigma <- params[2] a <- -0.5*length(data)*log(2*pi*sigma^2) b <- -0.5*sum((data-mu)^2) / (sigma^2) -(a+b) }<bytecode: 0x7fde86c5e8d8><environment: 0x7fde894427e8>
#ls()查看 nLL() 函数的环境ls(environment(nLL))[1] "data" "fixed" "params"

・返回的目标函数nLL()最下面的标签指示了目标函数的内部环境的位置;・目标函数nLL() 中的变量data、fixed、params都是自由变量,可以在make.NegLogLik() 函数的定义环境中找到,不必再声明。

make.NegLogLikfunction(data, fixed=c(FALSE,FALSE)) { params <- fixed function(p) { params[!fixed] <- p mu <- params[1] sigma <- params[2] a <- -0.5*length(data)*log(2*pi*sigma^2) b <- -0.5*sum((data-mu)^2) / (sigma^2) -(a+b) }}<bytecode: 0x7fddf9fc2080>

通常在全局环境中定义函数,如make.NegLogLik函数,则不会有用来标注环境的标签;当在一个函数内部定义了另一个函数的时候,就必须有一个指针 (pointer) 指向定义环境,R才能记住所有自由变量的值。

  1. 调用optim()对目标函数的参数进行调整优化

optim(c(mu = 0, sigma = 1), nLL)$par mu sigma 1.218239 1.787343

・optim()函数的par元素为最优解取值;・c(mu=0, sigma=1)为optim()函数中名为par的参数,设定各变量的初始值;・优化结果mu的估计值是1.2,sigma的估计值是1.78,接近真实值 (mu = 1, sigma = 2)。

  1. 可以固定参数,对其他参数优化,需要通过调用make.NegLogLik()重新构建目标函数。

#把变量fixed设置为(FALSE, 2),固定sigmanLL <- make.NegLogLik(normals, c(FALSE, 2))#optimize()最小化单变量函数optimize(nLL, c(-1, 3))$minimum[1] 1.217775

・调用make.NegLogLik(),固定mu=1,然后画出关于sigma的负的对数似然函数曲线。

nLL <- make.NegLogLik(normals, c(1, FALSE)) #构建了函数 nLL()x <- seq(1.7, 1.9, len = 100) y <- sapply(x, nLL) #对x中的值调用nLL()函数plot(x, exp(-(y - min(y))), type = "l")

・固定 sigma=2,画出关于mu的负的对数似然函数曲线。

nLL <- make.NegLogLik(normals, c(FALSE, 2)) x <- seq(0.5, 1.5, len = 100)y <- sapply(x, nLL)plot(x, exp(-(y - min(y))), type = "l")



相关阅读


数据科学02 | R语言程序设计-数据结构与函数

数据科学01- 数据科学家的工具箱 | PASS专题

单细胞转录组数据分析 | 界面版数据分析工具简介

不看后悔!GEO数据库10X单细胞测序原始测序测序数据(fastq)下载指南来啦

除了用肉眼你还可以在线预测m6A位点-附m6A数据库列表

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存