zoukankan      html  css  js  c++  java
  • 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"


  • 相关阅读:
    BZOJ 2212/BZOJ 3702
    BZOJ 4761 Cow Navigation
    BZOJ 3209 花神的数论题
    BZOJ 4760 Hoof, Paper, Scissors
    BZOJ 3620 似乎在梦中见过的样子
    BZOJ 3940 Censoring
    BZOJ 3942 Censoring
    BZOJ 3571 画框
    BZOJ 1937 最小生成树
    BZOJ 1058 报表统计
  • 原文地址:https://www.cnblogs.com/bigpo/p/4246575.html
Copyright © 2011-2022 走看看