【R语言与数据分析实战】R软件编程

1、流程控制

  (1) if语句

        ifelse()函数根据给定test值的真假,返回yes或no值。

ifelse(
    test,    #保存真假值的对象
    yes,     #test为真时,选择该值
    no       #test为假时,选择该值
)
# 例如
x <- c(1,2,3,4,5)
ifelse(x %% 2 == 0,"even","odd")

    [1] “odd” “even” “odd” “even” “odd”

  (2) 循环语句

        R中的循环语句分为for、while和respeat。

语法含义
for ( i in data) { 使用i的语句 }将data中的各值分别赋予变量i,同时针对每个i执行语句块中的语句
while (ond) { cond为真时要执行的语句}不断判断条件的cond的真假,条件cond为真时,执行{}中的语句,直到cond为假,退出循环
repeat { 要循环执行的语句 }反复执行{}中的语句,直至遇到退出条件。类似于其他语言中的do-while

        循环语句中,使用break与next语句可以调整循环语句的执行流程。

  • break:退出循环语句。
  • next:终止当前正在执行的语句块,进入下一循环。

2、运算

  (1) 数值运算

运算符与函数含义
+,-,*,/四则运算
n %% m求n/m的余数
n %/% m求n/m的商
n^m求n的m次方
exp(n)求e的n次方
log(x,base=exp(1))求logbase(x)。若不指定base,则计算loge(x)
log2(x),log10(x)分别计算log2(x)和log10(x)
sin(x),cos(x),tan(x)三角函数

  (2) 向量运算

        借助向量运算可以很容易地从数据框中保存的数据获取所需信息,其基本原理是通过向量数据框指定逻辑值以获取特定行。例如,

d <- data.frame(x=c(1,2,3,4,5),y=c("a","b","c","d","e"))
d[c(TRUE,FALSE,TRUE,FALSE,TRUE),]

        x  y
    1  1  a
    3  3  c
    5  5  e
        因此,只要通过向量运算构建行选择标准TRUE和FALSE,即可选定特定行。例如,下列示例选择x为偶数的行:

d[d$x %% 2 == 0,]

        x  y
    2  2  b
    4  4  d

  (3) NA处理

        数据包含NA时,运算结果都会变为NA。为了解决这一问题,R中许多函数都接受na.rm作为参数。数据包含NA时,使用na.rm指定是否要将NA值从运算中排除。

sum(c(1,2,3,NA))

    [1] NA

sum(c(1,2,3,NA),na.rm=TRUE)

    [1] 6
        常见的NA处理函数:

函数含义
na.fail(object,…)若object中包含NA,则失败
na.omit(object,…)若object中包含NA,则排除含有NA的行
na.exclude(object,…)若object中包含NA,则排除,这与na.omit相同。但使用naresid、napredict的函数中,通过NA排除的行会再次添加到结果
na.pass(object,…)即使object中包含NA,也使之通过
  • na.omit与na.exclude的差异
    假设有如下含有NA值的数据框。
df <- data.frame(x=1:5, y=seq(2,10,2))
df [3, 2]=NA
df

        X   Y
    1  1   2
    2  2   4
    3  3  NA
    4  4   8
    5  5  10
        假设这些数据遵循y=ax+b的线性模型,该模型可以使用线性回归函数lm()创建。若向创建的模型应用resid()函数,则可以求取线性模型的预测值与实际y值之间的残差(residual)。(有关线性回归、lm、resid函数的内容将在第8章讲解。)
        lm()函数带有na.action参数,该参数值不同,处理含有NA值的行的方法也不同。比如,若设置na.action=na.omit,则建模时含有NA值的第3行就被排除。因此,虽然df共有5行数据,但resid()的结果共有4个值,如下所示。

resid(lm(y ~ x, data=df, na.action=na.omit))

                         1                      2                       4                       5
    -2.982647e-16  3.439354e-16  1.612526e-16  -2.069233e-16
        若设置na.action =na.exclude,建模时含有NA的行仍然会被排除。但求残差时,含有NA的行的残差会在结果中显示,并记作NA。因此,resid()的结果长度与原数据长度是一致的。

resid(1m(y -x, data=df, na.action=na.exclude))

                         1                      2                      3                       4                       5
    -2.982647e-16  3.439354e-16                   NA  1.612526e-16  -2.069233e-16

3、定义函数

        R中定义函数的方法与其他编程语言中的类似,但也有如下几点不同。首先,返回值时要使用类似函数调用的形式“return(返回值)”,而非“return返回值”。其次,若省略return(),则函数最后一条语句的返回值即为整个函数的返回值。利用这一特征可以重写上述fibo()函数,如下所示。

fibo <- function(n) {
   if (n == 1 || n == 2) {
       1
   } else {
       fibo(n-1) + fibo(n-2)
   }
}

  (1) 可变长函数

        在R函数的帮助中,常常会看到参数列表中含有…。一方面,…表示函数的参数个数未知;另一方面,它也表示要传递给(在函数内部调用的)其他函数的参数。下列是可变长参数…的使用示例。函数f的定义中,使用…作为参数,将其逐个输出到屏幕。

 f <- function(...){
    args <- list(...)
    for (a in args){
        print(a)
    }
}
 f('3''4')

    [1] “3”
    [1] “4”

  (2) 嵌套函数

        借助嵌套函数可以提取某个函数内部要反复执行的一些操作,以形成一个函数。需要执行这些操作时,只需调用构建好的嵌套函数。这不仅能使代码变得简洁,也会让使用变得更简单。此外,由于内部函数也可以访问外部函数定义的变量,所以常用作闭包(closure)。

fc- function(x1){
    return(function(x2) {
        return(x1 +x2)
    })
}
g<-f(1)
g(2) #x1 = 1,x2= 2

    [1] 3

g2 <- f(2)
g2(2) #x1= 2,x2 = 2

    [1] 4
        如上代码所示,函数g()中,x1=1;函数g20中,x1=2,所以g(x2)计算的是1+x2,而g2(x2)计算的是2+x2。

4、作用域

        rm()删除指定环境中的对象;ls()返回对象名称。

rm( 
    …,                       #待删除的对象列表
    list=character(),         #含有待删除对象的向量
    envir=as.environment(pos) #待删除对象的环境
)
ls(
    name,    #对象所在环境的名称
    envir    #代替name直接设置环境
)            #返回值是包含对象名称的字符串向量。

        使用rm(list=ls())命令可以删除内存中的所有对象。
        若想在函数中为变量或全局变量赋值,则应使用<<-运算符。

b <- 0
f <- function(){
    a <- 1
    g <- function(){
        a <<- 2
        b <<- 2
        print(a)
        print(b)
    }
    g()
    print(a)
    print(b)    
}
f()

    [1] 2
    [1] 2
    [1] 2
    [1] 2

5、对象的不变性

        对象复制追踪函数

函数含义
tracemen(x)对对象复制进行追踪
untracemen(x)取消对象复制追踪

6、队列

        队列是一种“先进先出”(First In First Out, FIFO)的数据结构。可以将队列视为一个个人依次排成的一个队伍,处理事情时总先从站在队首的人开始,新来的人要排在队尾等待。队列由以下3个函数实现:

  • Enqueue:向队尾添加数据。
  • Dequeue:从队首获取数据,并将其从队列中删除。
  • Size:队列长度,即返回数据结构中保存的数据个数。

        编写支持这3种函数的队列,如下所示:

q <-c()
q size <- 0
enqueue <- function(data){
    q <<- c(q, data)
    q size <<- q_size + 1
} #入队
dequeue <- function(){
    first <- q[1]
    q <<- q[-1]
    q_size <<- q_size - 1
    return(first)
} #出队
size <- function(){
    return(q_size)
}

        上述代码中,队列使用向量q保存其数据,q_size记录队列中保存的数据个数。
        函数cnqueue()中,将从参数接收到的数据与q中的原有数据拼接为新向量,然后赋给变量此时,要使用<-赋值运算符为全局变量q赋值,最后将q_size的值增加1。
        函数dequeue()中,首先将q中保存的第一个元素赋给first,然后将除第一个数据外的所有数据保存到q,最后返回first,并且要将q_size减1。
        函数size()返回q的长度,即q_size。
        但是上述函数,在其他地方直接操作对q进行赋值,而不通过相关函数,在调用size函数时,队列长度不会发生变化。因此,需要将队列全部代码与相关变量隐藏到1个函数。

queue <-function(){
    q<-c()
    q_size<- 0
    
    enqueue <- function(data){
        q <<- c(q, data)
        q_size <<- q_size + 1
    }
    
    dequeue <- function(){
        first <- q[1]
        q <<- q[-1]
        q_size <<- q_size -1
        return(first)
    }
    
    size <- function(){
        return(q_size)
        return(list(enqueue=enqueue, dequeue=dequeue, size=size))
    }
}



ps:文章用于学习

[参考书目] 徐珉久,R语言与数据分析实战,2017

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值