• R笔记


    R语言编程艺术,第一章:快速入门
    1.生成n个基于N(0,1)分布的随机数rnorm(n)
    取绝对值abs(),
    取平均值mean(),
    取标准差sd()
    2.使用批处理命令:把下列命令保存在z.R的文件中
    pdf(“xh.pdf”) #保存为pdf格式的图形文件并命名为xh.pdf
    hist(rnorm(100)) #调用hist函数生成直方图
    dev.off() #关闭图形设备,即把生成的图形文件存盘
    如何调用呢?
    R CMD BATCH z.R
    3.创建一个向量:
    x <- c(1,2,4) #c是连接的意思
    q <- c(x,x,8) #可以创建包括向量的向量 q为 1 2 4 1 2 4 8
    4.元素的索引: R是从1开始索引的
    x[3]表示的时索引向量中的第三个元素
    索引片段:x[2:3]
    可以把这些索引值存储在片段中,使用赋值符号<-使用注释是一个好的习惯,在R中的交互式命令中也可以使用,因为查看历史命令可以帮助你回忆当时是怎么思考的
    5.R会内置一部分数据集,使用data()查看
    6.q()退出,注意在大型的数据集中,最好保存历史会话

    二 函数入门
    1.计算向量中余数的个数

    oddcount <- function(x){
    k <- 0 # 给计数器赋初值
    for(n in x){
    if(n %% 2 == 1) k <- k+1 # R的取余为 %%
    }
    return (k)
    }

    2.在函数内部使用的变量都是局部变量,他们在函数返回值之后就撤消了
    全局变量则是在函数之外创建的变量,在函数内部也可以访问:
    f <- function(x) return(x+y) #定义函数
    y <- 3
    f(5)的结果是 8
    3.关于函数调用,赋值的问题,先给定一个函数:
    f <- function(x=1,y,z) return(x+y+z)
    虽然函数缺省x的值,但是调用时还要小心
    f(2,3) #函数将把2重新赋给x,把3赋给y,z没有值,错误
    f(y=2,z=3) #指明变量的值,正确
    f(2,2,3) #函数将重新把x的值赋为2,然后y是2,z是3
    4.列表list
    创建一个列表吧
    x <- list(u=2,v="abc")
    索引列表中的值用$
    x$u
    5.矩阵
    如何创建矩阵?
    行绑定:rbind() 即按行绑定:
    m <- rbind(c(1,4),c(2,2))
    > m
         [,1] [,2]
    [1,]  1    4
    [2,]  2    2
    列绑定:cbind() 按列绑定:
    n <- cbind(c(1,4),c(2,2))
    > n
         [,1] [,2]
    [1,]  1    2
    [2,]  4    2
    6.混合型的数据矩阵称为数据框
    d <- data.frame(list(kids=c("Jack","Jill"),ages=c(12,10)))
    > d
    kids ages
    1 Jack 12
    2 Jill 10

    1.添加或删除向量元素
    实际上就是重新对变量赋值
    x <- c(1,2,3,5)
    x <- c(x[1:3],4,x[4]) #我想添加一个向量元素4使之变成(1,2,3,4,5)
    x <- c(x[1:3]) #我想删除一个向量元素5使之变成(1,2,3)
    2.关于循环的再认识
    循环的目的是什么?是遍历向量中各个元素的值?还是不仅要求值还想要取得该元素的序列?
    如果只要求使用元素的值,使用下列的写法:
    for(n in x){
    statement }
    如果不单单要求值,还要取得元素的索引号,使用下面的写法:
    for (i in 1:length(x)){
    statement } #这里的x[i]与上面的n相同,代表向量中各个元素的可能取值
    3.遍历取值的时候,应避免向量元素个数小于1
    正常情况下是这样的:
    x <- c(1,2,3)
    > 1:length(x)
    [1] 1 2 3
    如果是这样:
    x <- c()
    > 1:length(x)
    [1] 1 0 #这明显不是我们想要的结果
    4.矩阵在内存序列中是如何储存的?
    是按列存储的,不论是如何生成矩阵的,是按列绑定cbind,还是按行绑定rbind,在内存序列中
    都是按列存储的
    如何验证?
    m <- rbind(c(1,2),c(3,4)) #这里的矩阵m是按行绑定生成的
    > m
        [,1] [,2]
    [1,] 1     2
    [2,] 3     4
    > m + 10:13
        [,1] [,2]
    [1,] 11  14
    [2,] 14  17
    显然,矩阵m按列存储为一个四元向量(1,3,2,4),加上(10,11,12,13)得到(11,14,14,17)
    5.同多数脚本语言一样,R不需要事先声明变量,注意这里的"不需要"只是其中的一种方法.
    创建向量的另一种方法:(声明变量法)
    y <- vector(length=2) #为变量y分配两个存储空间,没有赋值的情况下,两个都是FALSE
    y[1] <- 5 #一旦对其中任何一个元素赋值,其它元素自动置为0,此时y[2]为0
    y[2] <- 12 #生成一个(5,12)的二元向量
    说明一下为什么需要上述的方法:如果在循环体中每次使用类似于y <- c(5,12)的赋值,会
    减慢代码的运行速度,因此使用上述方法在一开始就分配内存空间,而进入循环体后只是填充
    空间.
    另一种方法就是常见的
    y <- c(5,12)
    6.循环补齐
    (1)向量与向量相加
    如果长度不相等,短的就会自动与长的补齐,
    注意,这里不是补零!而是循环补
    c(1,2,3)
    c(1,2,3,1,2) #补成5位的
    c(1,2,3,1,2,3,1) #补成7位的
    (2)向量与矩阵相加
    注意,因为矩阵无法循环补齐,故只能是短向量与长矩阵相加时,会出现短向量循环补齐
    (3)矩阵与矩阵相加
    只能是相同行和列的矩阵相加,不存在补齐的情况!
    7.索引不连续的向量
    x <- c(1,5,2,0,5,6,7,8)
    > x[c(1,3,4)] #索引x向量的第一位,第三位和第四位元素
    [1] 1 2 0
    > x[1:3] #索引连续元素的方法:x向量的前三个元素
    [1] 1 5 2
    > x[c(1,1)] #重复索引第一位的元素
    [1] 1 1
    以上都是对R说我想要某某元素,还有一种方法是:我不想要某某元素,其它的都要:
    > x[c(-1)] #除了第一位元素,其它都要
    [1] 5 2 0 5 6 7 8
    > x[c(-3:-5)] #除了第三到第五位元素,其它都要
    [1] 1 5 6 7 8
    8.创建向量
    回忆下我们目前知道的创建向量的方法:
    x <- c(1,2,3,4,5,7,5,9)
    如果想创建连续值得向量(注意他们的步进都是1):
    x <- 1:8 #正向
    x <- 5:-2 #负向
    想改变步进的大小?没问题,使用seq()函数:
    x <- seq(from=12,to=29,by=3)
    > x #注意这里终止于27,而不是29,因为它们之间的间隔小于步进3
    [1] 12 15 18 21 24 27 #上述函数可以理解为生成开始于12,步进为3,最大不超过29的序列
    同样生成负向的序列:
    > seq(from=0.8,to=-0.1,length=10) #这里规定了向量的总长度,自动计算步进
    [1] 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0.0 -0.1
    seq()的另一个作用:
    seq(x)与1:length(x)的作用相同,甚至更优,因为对于空值x
    x <- c()
    > 1:length(x)
    [1] 1 0 #这明显不是我们想要的结果
    > seq(x)
    integer(0) #该结果会是上面循环迭代0次,符合我们的期望
    创建重复序列的向量:rep(x,times)
    > rep(c(1,3,8),4)
    [1] 1 3 8 1 3 8 1 3 8 1 3 8
    > rep(c(1,3,8),each=4) #每个元素重复4遍
    [1] 1 1 1 1 3 3 3 3 8 8 8 8
    9.布尔值求解any(),all()
    x <- 1:9
    > any(x>5) #x中有>5的元素吗?
    [1] TRUE
    > all(x>5) #x中所有元素都>5吗?
    [1] FALSE



    实例一:寻找连续出现1的游程
    x <- c(1,0,0,1,1,1,0,1,1)

    #version 1.0
    findruns <- function(x,k){ #k是指连续出现1的个数
    n <- length(x)
    runs <- NULL
    for (i in 1:(n-k+1)){ #为什么不是1:n?因为要保证连续的k个数比较
    if(all(x[i:(i+k-1)]==1)) #这个判断值真的是太绝妙了!
    runs <- c(runs,i) #重复赋值,可能会拖慢代码的运行速度
    }
    return(runs)
    }
    #version 2.0
    findruns <- function(x,k){
    n <- length(x)
    runs <- vector(length=n) #不同于上个版本的地方,先声明runs的变量
    count <- 0 #为runs分配的空间是用不完的,count计算用了多少位
    for (i in 1:(n-k+1)){
    if (all(x[i:(i+k-1)]==1)){
    count <- count + 1
    runs[count] <- i #这里count也充当runs的序列索引号
    }
    }
    if (count > 0){
    runs <- runs[1:count] #释放未利用的内存空间
    } else runs <- NULL
    return (runs)
    }



    实例二:预测离散值时间序列

    preda <- function(x,y){
    n <- length(x)
    k2 <- k/2 #如果在连续k天内1的数量>= k/2
    
    pred <- vector(length=n-k)
    for (i in 1:(n-k)) {
    if (sum(x[i:(i+k-1)]) >= k2) #如果在连续k天内1的数量>= k/2
    pred[i] <- 1 #那么预测下一个值为1
    else
    pred[i] <- 0 
    }
    return(mean(abs(pred-x[(k+1):n])))
    }

    但在实际中很少用诸如
    sum(x[i:(i+k-1)])计算连续k个元素之和,因为重复计算,这会拖慢代码速度
    我们可以使用cumsum()函数代替:cumsum是计算向量的累积和
    y <- c(5,2,-3,8)
    > cumsum(y)
    [1] 5 7 4 12
    比如我想计算第二个到第四个数的和
    x <- cumsum(y)
    x[4] - x[1]
    那第一个到第三个数之和呢? 为了统一形式:
    x[3] - x[0] 但R中向量元素是从零开始索引的,为了形式上的统一
    我们使用如下办法:
    csx <- c(0,cumsum(y))
    这样以来我们就可以写成
    csx[4] - scx[1] 来表示向量元素中第一个数到第三个数之和

    基于此,我们更改第一个版本的代码:

    preda <- function(x,y){
    n <- length(x)
    k2 <- k/2 #如果在连续k天内1的数量>= k/2
    
    pred <- vector(length=n-k)
    csx <- c(0,cumsum(x)) #新添的代码!
    for (i in 1:(n-k)) {
    if (csx[i+k] - csx[i] >= k2) #如果令i=1,k=3,该语句即为csx[4] - csx[1] #来表示向量元素中第一个数到第三个数之和
    pred[i] <- 1 #那么预测下一个值为1
    else
    pred[i] <- 0 
    }
    return(mean(abs(pred-x[(k+1):n])))
    }

    第三章:矩阵和数组
    1.如何创建矩阵
    > y <- matrix(c(1,2,3,4),nrow=2,ncol=2) #矩阵在R中是按列存储的
    > y
         [,1] [,2]
    [1,] 1     3
    [2,] 2     4
    该方法与之前的通过行(列)绑定的方法无异:
    > x <- cbind(c(1,2),c(3,4))
    > x
        [,1] [,2]
    [1,] 1   3
    [2,] 2   4
    > all(x==y)
    [1] TRUE
    录入数据时,有时希望录入的数据元素可以按行排列,
    这时只需令 byrow=1 即可,但是注意,矩阵在R中依然是按列存储的
    > m <- matrix(c(1,2,3,4,5,6),nrow=2,byrow=1)
    > m
         [,1] [,2] [,3]
    [1,] 1     2     3
    [2,] 4     5     6

    类似于向量的创建,矩阵还可以先声明,再赋值
    > y <- matrix(nrow=2,ncol=2)
    > y
         [,1] [,2]
    [1,] NA NA
    [2,] NA NA
    > y[1,1] <- 1
    > y[1,2] <- 3
    > y[2,1] <- 2
    > y[2,2] <- 4
    > y
        [,1] [,2]
    [1,] 1     3
    [2,] 2     4

    2.一般矩阵运算
    这里先介绍三种:
    数量乘法运算:3*y
    矩阵相加运算:y+y
    矩阵相乘运算:y %*% y

    3.矩阵索引:
    列索引: z[,2:3] #索引z矩阵的所有行,第二到第三列
    行索引: z[2:3,] #索引z矩阵的第二到第三列,所有的列
    不连续行的索引: z[c(1,3),]
    负值索引:即索引除去该值外的所有元素
    > y <- matrix(c(1,2,3,4,5,6),ncol=2) #只规定行或列即可
    > y
        [,1] [,2]
    [1,] 1   4
    [2,] 2   5
    [3,] 3   6
    > y[-2,] #索引y矩阵除第二行外的所有元素
         [,1] [,2]
    [1,] 1    4
    [2,] 3    6

    4.改变矩阵的值
    > m
         [,1] [,2] [,3]
    [1,] 1     2     3
    [2,] 4     5     6
    > m[,c(1,3)] <- matrix(c(1,2,3,4),nrow =2)
    > m
         [,1] [,2] [,3]
    [1,]  1     2     3

    5.矩阵元素的筛选:
    > y
          [,1] [,2]
    [1,] 1   4
    [2,] 2   5
    [3,] 3   6
    > y[y[,2]>=5,] #筛选出y矩阵中第二列>=5的所有行,并组成所有新的矩阵
         [,1] [,2]
    [1,] 2     5
    [2,] 3     6
    扩展案例:如何生成协方差矩阵?

    makecov <- function(rho,n){
    m <- matrix(nrow=n,ncol=n) #声明一个n行n列的矩阵
    m <- ifelse(row(m)==col(m),1,rho) #对角线元素为1,其它位置是协方差系数
    return(m)
    }

    > makecov(0.2,3)

         [,1] [,2] [,3]
    [1,] 1.0 0.2 0.2
    [2,] 0.2 1.0 0.2
    [3,] 0.2 0.2 1.0

    6.apply()函数
    有时我们要对矩阵的行或列做这样或那样的运算,apply()函数就派上用场了,
    apply函数有三个参数apply(m,dimcode,f,fargs)
    m 矩阵名称
    dimcode:只有两个值,1把函数运用到每一行,2把函数运用到每一列
    f 运用到每行或每列的函数
    fargs 函数的参数
    > copymaj <- function(rw,d){
    + maj <- sum(rw[1:d])/d #计算每行前d个数的平均值
    + return(ifelse(maj>0.5,1,0)) #>0.5返回1,否则返回0
    + }
    > x <- matrix(c(1,0,1,1,0,1,1,1,1,0,1,0,0,1,1,0,1,1,1,0),nrow=4,byrow=T)
    > x #参数byrow=T表示录入的元素按行排列
         [,1] [,2] [,3] [,4] [,5]
    [1,] 1     0     1     1     0
    [2,] 1     1     1     1     0
    [3,] 1     0     0     1     1
    [4,] 0     1     1     1     0
    > apply(x,1,copymaj,3)
    [1] 1 1 0 1 #每行的结果都是按列存储的,共有4行,所以结果是4列
    > apply(x,1,copymaj,2)
    [1] 0 1 0 0
    > apply(x,2,copymaj,2) #对矩阵的每列进行运算,矩阵有5列,结果也是5列
    [1] 1 0 1 1 0
    > apply(x,2,copymaj,3)
    [1] 1 0 1 1 0
    扩展案例:寻找异常值:

    findols <- function(x){
    findol <- function(xrow){
    mdn <- median(xrow) #寻找每一行的中位数
    devs <- abs(xrow - mdn) #把每一行元素与中位数的差值赋给devs向量
    return(which.max(devs)) #找到devs向量中最大元素的位置
    }
    return(apply(x,1,findol)) #把findol函数用到x矩阵的每一行
    }

    > y <- matrix(c(1,4,6,3,2,5,7,29,53,76,3,2,1,987,3,56,54,22,2,1,8),nrow=3,byrow=T)

    > y
          [,1] [,2] [,3] [,4] [,5] [,6] [,7]
    [1,] 1     4     6     3     2     5     7
    [2,] 29   53   76   3     2     1   987
    [3,] 3    56    54   22    2    1     8
    > findols(y)
    [1] 1 7 2

    7.和向量一样,在循环中重复不断的创建矩阵是很浪费时间的行为,
    一个比较好的办法就是,在循环体外先声明一个空的矩阵,
    然后在循环中为矩阵赋值

    8.避免意外降维
    当我们从某一矩阵抽取其中的一行作为子矩阵时,得到的却变为了一个向量,
    > z <- matrix(1:8,nrow=4)
    > z
        [,1] [,2]
    [1,] 1     5
    [2,] 2     6
    [3,] 3     7
    [4,] 4     8
    > r <- z[2,]
    > r
    [1] 2 6
    因为这里
    > nrow(r)
    NULL #故r是一个向量,这与我们的预期不符,
    解决办法就是使用drop参数
    > r <- z[2,,drop=FALSE]
    > r
        [,1] [,2]
    [1,] 2   6
    此时有:
    > nrow(r)
    [1] 1
    这里提供另外的一个小技巧:把向量变为矩阵as.matrix()
    > u <- 1:3
    > u
    [1] 1 2 3
    > as.matrix(u)
         [,1]
    [1,] 1
    [2,] 2
    [3,] 3

    9.给矩阵的行或列取名字
    > z
        [,1] [,2]
    [1,] 1  5
    [2,] 2  6
    [3,] 3  7
    [4,] 4  8

    > colnames(z) <- c("a","b") #给z矩阵的列重新命名
    > z
          a b
    [1,] 1 5
    [2,] 2 6
    [3,] 3 7
    [4,] 4 8
    > rownames(z) <- c("甲","乙","丙","丁") #给z矩阵的行重新命名
    > z
        a b
    甲 1 5
    乙 2 6
    丙 3 7
    丁 4 8
    不过索引的时候也要加上引号:
    > z[c("甲","丙"),]
        a b
    甲 1 5
    丙 3 7

    10.高维数组
    高维数组其实就是矩阵的集合,有三个维度
    生成一个高维的数组:
    > firsttest <- matrix(c(46,21,50,30,25,50),nrow=3)
    > secondtest <- matrix(c(46,41,50,43,35,50),ncol=2)
    > firsttest
         [,1] [,2]
    [1,] 46 30
    [2,] 21 25
    [3,] 50 50
    > secondtest
         [,1] [,2]
    [1,] 46 43
    [2,] 41 35
    [3,] 50 50
    > tests <- array(data=c(firsttest,secondtest),dim=c(3,2,2))
    > tests #注意array中,有数据data部分和维度dim部分
    , , 1 #其中dim=c(x,y,n)中的n是data=c(a,b,c,...)中的矩阵个数

        [,1] [,2]
    [1,] 46 30
    [2,] 21 25
    [3,] 50 50

    , , 2

        [,1] [,2]
    [1,] 46 43
    [2,] 41 35
    [3,] 50 50

    第四章 列表
    1.一个简单地列表如下:
    > j <- list(name="Joe",salary=55000,union=T)
    > j
    $name #各组件的名字叫做"标签"(可以不指定)
    [1] "Joe"

    $salary #标签
    [1] 55000

    $union #标签
    [1] TRUE
    因为列表是向量,故可以用vector创建列表:
    > z <- vector(mode="list") #声明一个模式是"列表"的向量
    > z[["name"]] <- "Pony" #然后可以给列表不断的赋值
    > z[["salary"]] <- 33
    ...

    2.三种方法索引列表中的各组件:
    > j$name #列表名+$+组件名称
    [1] "Joe"
    > j[[1]] #列表名后跟双层中括号,括号内为索引组件在列表中得序号
    [1] "Joe"
    > j[["name"]] #列表名后跟双层中括号,括号内为带有双引号的组件名称
    [1] "Joe"
    #注意与使用单层中括号的区别
    > j["name"] #使用单层中括号返回的是该组件及组件的内容,可以视为一个子列表
    $name #使用双层中括号返回的是该组件的内容
    [1] "Joe"

    3.增加或删除列表元素:这里的列表元素指的是组件
    只能增加或删除组件,然后给组件赋值
    > z <- list(a="abc",b=12)
    > z
    $a
    [1] "abc"

    $b
    [1] 12

    > z$c <- "sailing" #增加一个组件c并赋值为sailing
    > z
    $a
    [1] "abc"

    $b
    [1] 12

    $c                #增加的组件c
    [1] "sailing"  #及内容
    如何删除组件b呢?
    只需给组件b赋值为NULL即可
    > z$b <- NULL #删除组件b的一种方法
    > z
    $a
    [1] "abc"

    $c #注意删除一个组件后,其它组件在列表中的序号可能会发生变动
    [1] "sailing"
    注意隐藏的类型转换
    > z[1:3] <- c(168,"Cool",TRUE) #z中各组件的内容全部被视为character型
    > z
    [[1]]
    [1] "168"

    [[2]]
    [1] "Cool"

    [[3]]
    [1] "TRUE"
    > class(z[[3]])
    [1] "character"

    > z[1:3] <- c(168,FALSE,TRUE) #z中各组件的内容全部被视为numeric型
    > z
    [[1]]
    [1] 168

    [[2]]
    [1] 0

    [[3]]
    [1] 1
    > class(z[[3]])
    [1] "numeric"
    > z[1:3] <- c(TRUE,FALSE,TRUE) #这个当然都为为logical型
    > z
    [[1]]
    [1] TRUE

    [[2]]
    [1] FALSE

    [[3]]
    [1] TRUE
    > class(z[[3]])
    [1] "logical"
    上面三个例子说明了什么?
    当要创建一个列表时,如果使用索引添加新组件,则c()中的内容会被置为统一数据类型
    此时应加以关注,避免产生非预期的结果!
    最后,还可以把多个列表拼接成一个:
    > c(list("Joe",55000,T),list(5))
    [[1]]
    [1] "Joe"

    [[2]]
    [1] 55000

    [[3]]
    [1] TRUE

    [[4]]
    [1] 5
    给同一个组件添加多个值:
    > z[[1]] <- c(z[[1]],123)
    > z
    [[1]]
    [1] "168" "123" #组件1中含有两个值

    [[2]]
    [1] "Cool"

    [[3]]
    [1] "TRUE"

    4.访问列表元素和值
    获取组件名称:标签
    > names(j)
    [1] "name" "salary" "union"
    去列表化:unlist()
    在去列表化的时候,只要有可能,列表的元素都强制被转换成一种共同存储模式
    > wu <- unlist(j)
    > wu
    name salary union
    "Pony" "55000" "TRUE"
    > class(wu)
    [1] "character"
    这里的wu实际是带有名字的字符串向量,为使看起来更像向量,可以把名字置空
    > names(wu) <- NULL #另一种方法是去名字化: unname()
    > wu
    [1] "Pony" "55000" "TRUE"

    5.在列表上使用apply()函数
    lapply()把函数应用到每一个列表元素中:
    > j <- list(1:3,25:27) #生成一个具有两个元素的列表
    > j
    [[1]]
    [1] 1 2 3

    [[2]]
    [1] 25 26 27

    > lapply(j,median) #对列表中每个元素应用median函数
    [[1]]
    [1] 2

    [[2]]
    [1] 26
    如果想把返回的结果转化成矩阵或向量形式,则可以使用sapply()
    > sapply(j,median)
    [1] 2 26

    6.递归型列表
    > b <- list(u=5,v=12)
    > c <- list(w=13)
    > a <- list("A"=b,"B"=c)
    > a
    $A
    $A$u #第一个组件A中包含u组件
    [1] 5

    $A$v #和v组件
    [1] 12


    $B #第二个组件B中包含w组件
    $B$w
    [1] 13

    第五章:数据框
    1.创建数据框
    > kids <- c("Jack","Jill")
    > ages <- c(12,10)
    > d <- data.frame(kids,ages) #创建数据框使用data.frame(col1,col2,col3...)
    > d #其中列向量col1,col2,...可以是任何数据类型
    kids ages
    1 Jack 12
    2 Jill 10
    2.访问数据框中各组件
    > d$kids #和列表的方式一样
    [1] Jack Jill
    Levels: Jack Jill
    > d[[1]]
    [1] Jack Jill
    Levels: Jack Jill
    > str(d) #str()函数查看d的内部结构
    'data.frame': 2 obs. of 2 variables:
    $ kids: Factor w/ 2 levels "Jack","Jill": 1 2
    $ ages: num 12 10
    3.提取子数据框
    首先创建一个考试成绩的数据框
    > Exam.1 <- c(2.0,3.3,4.0,2.3,2.3,3.3)
    > Exam.2 <- c(3.3,2.0,4.0,0.0,1.0,3.7)
    > Quiz <- c(4.0,3.7,4.0,3.3,3.3,4.0)
    > examsquiz <- data.frame(Exam.1,Exam.2,Quiz)
    > examsquiz
    Exam.1 Exam.2 Quiz
    1 2.0 3.3 4.0
    2 3.3 2.0 3.7
    3 4.0 4.0 4.0
    4 2.3 0.0 3.3
    5 2.3 1.0 3.3
    6 3.3 3.7 4.0 
    > examsquiz[2:5,] #提取2到5行
    Exam.1 Exam.2 Quiz
    2 3.3 2 3.7
    3 4.0 4 4.0
    4 2.3 0 3.3
    5 2.3 1 3.3
    > examsquiz[2:5,2,drop=FALSE] #为了避免"降维",使用"drop=FALSE"这个参数
    Exam.2
    2 2
    3 4
    4 0
    5 1
    数据筛选
    > examsquiz[examsquiz$Exam.1>=3,]
    Exam.1 Exam.2 Quiz
    2 3.3 2.0 3.7
    3 4.0 4.0 4.0
    6 3.3 3.7 4.0
    或者使用subset()函数
    > subset(examsquiz,Exam.1>=2.8)
    Exam.1 Exam.2 Quiz
    2 3.3 2.0 3.7
    3 4.0 4.0 4.0
    6 3.3 3.7 4.0

    4.缺失值NA的处理
    我们为examsquiz添加一行带有NA的数据
    > examsquiz <- rbind(examsquiz,list(3.7,NA,3.8))
    > examsquiz
    Exam.1 Exam.2 Quiz
    1 2.0 3.3 4.0
    2 3.3 2.0 3.7
    3 4.0 4.0 4.0
    4 2.3 0.0 3.3
    5 2.3 1.0 3.3
    6 3.3 3.7 4.0
    7 3.7 NA 3.8
    计算每一列的平均值:
    > apply(examsquiz,2,mean)
    Exam.1 Exam.2 Quiz
    2.985714 NA 3.728571
    第二列的均值竟然是NA!这显然不是我们所期望的,
    我们可以为mean函数增加一个参数使之可以忽视NA
    > apply(examsquiz,2,mean,na.rm=TRUE)
    Exam.1 Exam.2 Quiz
    2.985714 2.333333 3.728571 #计算Exam.2的均值时忽视了第七个学生的成绩
    5.为数据框添加新的列(行)的另一种方法
    上面已展示了如何使用rbind()或cbind()为数据框增添元素
    还可以使用这样:
    > examsquiz$Examdiff <- examsquiz$Exam.1 - examsquiz$Exam.2
    > examsquiz
    Exam.1 Exam.2 Quiz Examdiff
    1 2.0 3.3 4.0 -1.3
    2 3.3 2.0 3.7 1.3
    3 4.0 4.0 4.0 0.0
    4 2.3 0.0 3.3 2.3
    5 2.3 1.0 3.3 1.3
    6 3.3 3.7 4.0 -0.4
    7 3.7 NA 3.8 NA
    6.上面的NA看着很讨厌人,这里有一个方法去除
    > examsquiz[complete.cases(examsquiz),]
    Exam.1 Exam.2 Quiz Examdiff
    1 2.0 3.3 4.0 -1.3
    2 3.3 2.0 3.7 1.3
    3 4.0 4.0 4.0 0.0
    4 2.3 0.0 3.3 2.3
    5 2.3 1.0 3.3 1.3
    6 3.3 3.7 4.0 -0.4
    这里的complete.cases()作用是这样的:
    > complete.cases(examsquiz)
    [1] TRUE TRUE TRUE TRUE TRUE TRUE FALSE
    可以检测出哪一行的数据是不完整的
    7.合并数据框
    先给出两个含有相同元素的数据框
    > d1 <- data.frame(kids=c("Jalk","Jill","Jillian","John"),states=c("CA","MA","MA","HI"))
    > d1
    kids states
    1 Jack CA
    2 Jill MA
    3 Jillian MA
    4 John HI
    > d2 <- data.frame(ages=c(10,7,12),kids=c("Jill","Lillian","Jack"))
    > d2
    ages kids
    1 10 Jill
    2 7 Lillian
    3 12 Jack
    合并
    > d <- merge(d1,d2) #这两个数据框中都有kids这个组件,合并相同的值"Jack","Jill"
    > d
    kids states ages #组件states来自于d1,组件ages来自于d2
    1 Jack CA 12
    2 Jill MA 10
    另一种情况是:即使组件名字不同,但是内容一样时,依然可以通过一种方法合并
    > d3 <- data.frame(pals=c("Jack","Jill","Lillian"),ages=c(12,10,7))
    > d3
    pals ages
    1 Jack 12
    2 Jill 10
    3 Lillian 7
    > d1 <- cbind(d1,ages=c(10,7,12,9))
    > d1
    kids states ages
    1 Jack CA 10
    2 Jill MA 7
    3 Jillian MA 12
    4 John HI 9
    > merge(d1,d3,by.x="kids",by.y="pals")
    kids states ages.x ages.y #把d1中的kids与d2中的pals进行合并
    1 Jack CA 10 12
    2 Jill MA 7 10
    但如果两个数据框含有两个或两个以上的组件,且各有相同的值,那么如何确定合并
    的组件?
    > d1
    kids states ages
    1 Jack CA 10
    2 Jill MA 7
    3 Jillian MA 12
    4 John HI 9
    > d2
    ages kids
    1 10 Jill
    2 7 John
    3 12 Jack
    > merge(d1,d2) #R也不知该按kids合并还是按ages合并了
    [1] kids ages states
    <0 行> (或0-长度的row.names)
    这时,可以加个参数用于指定按哪个组件进行合并
    > merge(d1,d2,by.x="kids",by.y="kids") #把d1中的kids与d2中的kids合并
    kids states ages.x ages.y
    1 Jack CA 10 12
    2 Jill MA 7 10
    3 John HI 9 7
    > merge(d1,d2,by.x="ages",by.y="ages") #把d1中的ages与d2中的ages合并
    ages kids.x states kids.y
    1 7 Jill MA John
    2 10 Jack CA Jill
    3 12 Jillian MA Jack
    但这个数据框好像只能应用于两个数据框,我试验了三个,但直接被无视了:
    > d3
    pals ages
    1 Jack 3
    2 Jill 6
    3 Lillian 8
    > merge(d1,d2,d3,by.x="kids",by.y="kids",by.z="pals")
    kids states ages.x ages.y #d3中的数据未被合并进来
    1 Jack CA 10 12
    2 Jill MA 7 10
    3 John HI 9 7
    8.应用于数据框的函数
    > d1
    kids states ages
    1 Jack CA 10
    2 Jill MA 7
    3 Jillian MA 12
    4 John HI 9
    > lapply(d1,sort) #对数据框的每列进行排序,返回的是列表
    $kids
    [1] "Jack" "Jill" "Jillian" "John"

    $states
    [1] CA HI MA MA
    Levels: CA HI MA

    $ages
    [1] 7 9 10 12

    > as.data.frame(lapply(d1,sort)) #把列表转化成数据框,但结果没什么意义了
    kids states ages
    1 Jack CA 7
    2 Jill HI 9
    3 Jillian MA 10
    4 John MA 12

    第六章 因子和表
    1.因子与水平
    > e <- c(2,45,13,2,4,9,6,87,12,1,2,13)
    > e
    [1] 2 45 13 2 4 9 6 87 12 1 2 13
    > ef <- factor(e) #把向量e转化成因子ef
    > ef #因子的结构包括以下:向量元素的值,向量的水平
    [1] 2 45 13 2 4 9 6 87 12 1 2 13 #元素的值
    Levels: 1 2 4 6 9 12 13 45 87 #按元素的值从小到大排列,且不重复.
    > str(ef)
    Factor w/ 9 levels "1","2","4","6",..: 2 8 7 2 3 5 4 9 6 1 ...
    元素的值按水平位置的索引,比如2排在水平级的第二位,45排在水平级的第八位,
    13排在水平级的第七位.
    我们在定义一个因子时,可以通过定义水平而预置数据
    > x <- c(5,12,13,12)
    > xff <- factor(x,levels=c(5,12,13,18))
    > xff
    [1] 5 12 13 12
    Levels: 5 12 13 18 #"水平级"告诉我们,将来因子中有可能加入18这个值
    > xff[2] <- 18
    > xff
    [1] 5 18 13 12
    Levels: 5 12 13 18
    而若加入一个水平级里面没有的值,可能会得到一个警告,并且不会成功
    > xff[2] <- 88
    警告信息:
    In `[<-.factor`(`*tmp*`, 2, value = 88) :
    invalid factor level, NA generated
    > xff
    [1] 5 <NA> 13 12 #88未被加入
    Levels: 5 12 13 18
    2.因子常用函数
    tspply(x,f,g) #x是向量,f是因子或因子列表,g是函数
    tapply()执行的操作是:将向量x按因子水平分组,得到x的子向量,再把函数g应用到这些子向量中
    > ages <- c(25,26,55,37,21,42)
    > affils <- c("R","D","D","R","U","D")

    > tapply(ages,affils,mean) #affils的因子水平,是D R U
    D R U #x的子向量是D:26,55,42 R:25,37 U:21
    41 31 21 #每个子向量求平均得 D:41 R:31 U:21
    > tapply(affils,ages,mean)
    21 25 26 37 42 55 #不要把affils和ages弄反了,这个是错误的!!!
    NA NA NA NA NA NA
    警告信息:
    1: In mean.default(X[[1L]], ...) : 参数不是数值也不是逻辑值:回覆NA
    2: In mean.default(X[[2L]], ...) : 参数不是数值也不是逻辑值:回覆NA
    3: In mean.default(X[[3L]], ...) : 参数不是数值也不是逻辑值:回覆NA
    4: In mean.default(X[[4L]], ...) : 参数不是数值也不是逻辑值:回覆NA
    5: In mean.default(X[[5L]], ...) : 参数不是数值也不是逻辑值:回覆NA
    6: In mean.default(X[[6L]], ...) : 参数不是数值也不是逻辑值:回覆NA
    一个含有两个因子的例子:
    > d <- data.frame(gender=c("M","M","F","M","F","F"),
    + age=c(47,59,21,32,33,24),
    + income=c(55000,88000,32450,76500,123000,45650))
    > d #关于数据框的生成,如果使用data.frame(list(...))也是可以的
    gender age income
    1 M 47 55000
    2 M 59 88000
    3 F 21 32450
    4 M 32 76500
    5 F 33 123000
    6 F 24 45650
    我想按性别及年龄是否超过25岁分组求平均,为此我们先为数据框增加一个组件
    > d$over25 <- ifelse(d$age>25,1,0)
    > d
    gender age income over25
    1 M 47 55000 1
    2 M 59 88000 1
    3 F 21 32450 0
    4 M 32 76500 1
    5 F 33 123000 1
    6 F 24 45650 0
    按照性别,是否过25岁这两个维度求平均:
    > tapply(d$income,list(d$gender,d$over25),mean)
    0 1
    F 39050 123000.00
    M NA 73166.67
    当然,我们可以只按性别求平均:
    > tapply(d$income,d$gender,mean)
    F M
    67033.33 73166.67
    也可以只按是否过25岁求平均:
    > tapply(d$income,d$over25,mean)
    0 1
    39050 85625

    split()函数
    类比于tapply(),split()只做到:将向量x按因子水平分组,得到x的子向量这一步就结束了
    > split(d$income,d$gender)
    $F #女性的收入
    [1] 32450 123000 45650

    $M #男性的收入
    [1] 55000 88000 76500

    > split(d$income,list(d$over25,d$gender))
    $`0.F` #未过25岁的女性的收入
    [1] 32450 45650

    $`1.F` #25岁以上女性的收入
    [1] 123000

    $`0.M` #不到25岁男性的收入
    numeric(0)

    $`1.M` #25岁以上男性的收入
    [1] 55000 88000 76500
    使用split()可以快速索引文本词汇出现的位置
    split(1:length(txt),txt) #txt是一个包括所有文本词汇的因子

    by()的调用方式与tapply()类似,不同的是,tapply的第一个参数必须是向量,而by()支持矩阵
    和数据框

    3.表的操作
    > f1 <- list(c(5,12,13,12,13,5,13),c("a","b","a","a","b","a","a"))
    > table(f1) #表返回的是因子f1中各元素的频数
    f1.2
    f1.1 a b
    5 2 0
    12 1 1
    13 2 1
    再来看一个三维的表:
    > v <- data.frame(gender=c("M","M","F","M","F","F"),race=c("W","W","A","O","B","B"),pol=c("L","L","C","L","L","C"))
    > v
    gender race pol
    1 M W L
    2 M W L
    3 F A C
    4 M O L
    5 F B L
    6 F B C
    > vt <- table(v) #表是以二维的结构展示的
    > vt
    , , pol = C

    race
    gender A B O W
    F 1 1 0 0
    M 0 0 0 0

    , , pol = L

    race
    gender A B O W
    F 0 1 0 0
    M 0 0 1 2
    使用addmargins()函数计算表的边际值:
    > table(f1)
    f1.2
    f1.1 a b
    5 2 0
    12 1 1
    13 2 1
    > addmargins(table(f1))
    f1.2
    f1.1 a b Sum
    5 2 0 2
    12 1 1 2
    13 2 1 3
    Sum 5 2 7
    使用dimnames()函数获得表的维度的名称
    > dimnames(table(f1))
    $f1.1
    [1] "5" "12" "13"

    $f1.2
    [1] "a" "b"


  • 相关阅读:
    如何在Word中排出漂亮的代码
    html如何设置表格单元格内容垂直居中?
    Markdown&Latex学习笔记,qwq
    洛谷P1111
    洛谷 P4961
    线段树
    自我介绍&友链
    洛谷 P3367 【模板】并查集
    luogu P1074 靶形数独
    SPOJ简介。
  • 原文地址:https://www.cnblogs.com/bigpo/p/4246575.html
Copyright © 2020-2023  润新知