• R语言编程艺术_第六章_因子和表


    一、因子与水平

    1、简单直接的认识因子和水平

      因子可以简单的理解为包含了更多信息的向量。即因子=向量 + 水平。(当然实际上它们内部机理不同)。水平是对于向量中不同值的记录,以下面代码为例:

    > x <- c(5, 12, 13, 12)
    > x
    [1]  5 12 13 12
    > xf <- factor(x)
    > xf
    [1] 5  12 13 12
    Levels: 5 12 13

     但是我们说到因子的长度时,则定义为数据的长度,而非水平的个数。

    > length(xf)
    [1] 4
    

     2、因子的增,删,改,查(好了这里其实只有

     在增加因子的水平时,我们需要提前插入,不能像矩阵或是列表那样随加随到。

    > x <- c(5,12,13,12)
    > xf <- factor(x)
    > xff <- factor(x, levels = c(5, 12, 13, 88))
    > xff
    [1] 5  12 13 12
    Levels: 5 12 13 88
    

      比如用下面的方法,就会提示非法插入。

    xff[3] <- 6
    Warning message:
    In `[<-.factor`(`*tmp*`, 3, value = 6) : invalid factor level, NA generated
    > xff
    

    二、因子的常用函数

      1、tapply函数

      典型的tapply函数用法为tapply(x, f, g), x为向量,f为因子或因子列表,g()为所需要对x运用的函数。

      tapply函数的执行操作的流程:先将x按照因子f来分组,得到若干个子向量,然后针对每个子向量使用g()函数,最后返回一个分好类的矩阵。

    > ages <- c(25,26,55,37,21,42)
    > affils <- c("R", "D", "D", "R", "U", "D")
    > tapply(ages, affils, mean)
     D  R  U 
    41 31 21 
    

      这个例子就是分别针对每个不同的党派(民主党,共和党,无党派)的人的年龄进行了求平均数。

      然后下面的一个例子更进一步,在有两个或两个以上因子存在的情况下,也就是需要用因子列表来进行操作。

    d <-  data.frame(list(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
      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
    > 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
    > tapply(d$income, list(d$gender, d$over25), mean)
          0         1
    F 39050 123000.00
    M    NA  73166.67
    

     上面的程序实现的功能是:分别按照性别和年龄(两个因子)来求收入的平均水平。所以就分成了四个子向量:

    • 25岁以下男性
    • 25岁以下女性
    • 25岁以上男性
    • 25岁以上女性

      而这里比较巧妙的就是在于对加了一列“over 25”来对年龄做一个简单的区分,这就极大的方便了后面的tapply()使用。

    2、split ()函数 

       split()执行的功能是将向量按照因子水平分组,然后返回一个列表。继续对上面的数据框d操作。

    split(d$income, list(d$gender, d$over25))
    $F.0
    [1] 32450 45650
    
    $M.0
    numeric(0)
    
    $F.1
    [1] 123000
    
    $M.1
    [1] 55000 88000 76500
    

      另一个关于鲍鱼性别的问题,我们可以通过split函数快速知道哪几个位置分别是什么性别的鲍鱼。

    split(1:7, g)
    $F
    [1] 2 3 7
    
    $I
    [1] 4
    
    $M
    [1] 1 5 6
    

      3、by() 函数

      by() 函数和tapply()的作用方式类似,但是它的作用对象不仅仅是向量,可以说矩阵或数据框。下面一个就是利用by()函数做回归分析的例子。读取的文件来自于课本附属的链接(可惜的是数据太太太残缺了)

    > aba2 <- read.csv("E:/files_for_R/abalone.data", header = F)
    > #read.table vs .csv :.table默认文件内容用“/”分隔,“.csv"默认为","
    > colnames(aba2) <-  c("gender", "length", "diameter","height","wholewt", "shuckedwt", "viscwt", "shellwt", "rings")
    > by(aba2, aba2$gender, function(m) lm(m[,2]~m[,3]))
    aba2$gender: F
    
    Call:
    lm(formula = m[, 2] ~ m[, 3])
    
    Coefficients:
    (Intercept)       m[, 3]  
        0.04288      1.17918  
    
    --------------------------------------------------------- 
    aba2$gender: I
    
    Call:
    lm(formula = m[, 2] ~ m[, 3])
    
    Coefficients:
    (Intercept)       m[, 3]  
        0.02997      1.21833  
    
    --------------------------------------------------------- 
    aba2$gender: M
    
    Call:
    lm(formula = m[, 2] ~ m[, 3])
    
    Coefficients:
    (Intercept)       m[, 3]  
        0.03653      1.19480  
    

      书里边给的数据不完整,少了一个header,所以自己给加了一段。自己发挥的如下。

    colnames(aba2) <-  c("gender", "length", "diameter","height","wholewt", "shuckedwt", "viscwt", "shellwt", "rings")三 

     三、表的操作

    1、关于R语言中的table函数

    到目前为止我们一共遇到过两个与table有关的函数: 一个是read.table(),另一个是table()。read.table()用以读取数据文件,默认分隔符为“ ”;table()函数则是对因子或因子的列表进行处理,从而获得一个列联表,也就是一种记录频数的方法。

    2、table()函数详细操作

    首先我们先得到这样子一个数据框

    > ct <- data.frame( 
    +   Vote.for.X = factor(c("yes", "yes", "no", "not sure", "no")),
    +   Voted.for.X = factor(c("yes", "no", "no", "yes", "no"))
    +   )
    
    > ct
      Vote.for.X Voted.for.X
    1        yes         yes
    2        yes          no
    3         no          no
    4   not sure         yes
    5         no          no
    

      使用table()函数进行处理之后,就得到了如下的频数表。

    > cttab <- table(ct)
    > cttab
              Voted.for.X
    Vote.for.X no yes
      no        2   0
      not sure  0   1
      yes       1   1
    

      同样的,若果你有三维的数据,table() 可以以两维的表格的形式打出来。这里并不想再举例了(懒。。。。。)

    3、表中有关矩阵和类似数组的操作

      3.1 访问单元格频数

    这里的操作其实和列表一样。依然以上面的cttab为例。

    > class(cttab)
    [1] "table"
    > cttab[,1]
          no not sure      yes 
           2        0        1 
    > class(cttab)
    [1] "table"
    > cttab[,1]
          no not sure      yes 
           2        0        1 
    > cttab[1,1]
    [1] 2
    

      3.2 等比例改变单元格频数

    > cttab/5
              Voted.for.X
    Vote.for.X  no yes
      no       0.4 0.0
      not sure 0.0 0.2
      yes      0.2 0.2
    

      3.3 得到表的边界值

    • 变量的边界值:保持该变量为常数时对其他变量对应的数值求和所得到的值。
    •  比较直接的方法是直接通过apply( )函数来实现。
    > apply(cttab, 1, sum)
          no not sure      yes 
           2        1        2 
    
    •  更加直接的方法是利用添加边界值的函数 addmargins( ),直接多出两个维度的边界值
    > addmargins(cttab)
              Voted.for.X
    Vote.for.X no yes Sum
      no        2   0   2
      not sure  0   1   1
      yes       1   1   2
      Sum       3   2   5
    

     4、扩展案例:在表中寻找频数最高的单元格

    整个函数的设计思路可以按照以下路径来:

    • 添加新的一列Freq来表示各类数据的频数(这可以通过as.data.frame来实现)
    • 对各行按照频数大小进行排序(通过order()函数来实现)
    • 按照要求区前k行。
    • 具体代码如下:
    tabdom <- function(tbl, k){
    #create a data frame representing tbl, add a Freq column 
     tablframe <- as.data.frame(tbl)
    #determine the proper position of the frequencies in an ordered frequency
    #rearrange the data frame, get the first k rows
      tblfreord <- order(tablframe$Freq, decreasing = TRUE)
      dom <- tablframe[tblfreord,][1:k,]
      return(dom)
    }
    

      

  • 相关阅读:
    uniapp,获取用户地理位置信息授权,如果拒绝的话需要引导用户重新请求授权操作
    sql group by 之别扭
    echart.js 遇到的问题及解决
    sql 时间截取 分组 获得小时数据常用的方法
    使用JSON JavaScriptSerializer 进行序列化或反序列化时出错。字符串的长度超过了为 maxJsonLength属性
    C#中Math.Round()实现中国式四舍五入
    layui js出现一个form内和外的button 事件怪事
    Sql Server 查询指定范围(一周,一月,本周,本月等)内的数据
    java jdk1.6低版本ssm 源码的的在idea的搭建
    一个 jQuery循环获取点击事件,显示tab 子页
  • 原文地址:https://www.cnblogs.com/dingtou00/p/9033410.html
Copyright © 2020-2023  润新知