1. 程式人生 > >R語言編程藝術_第六章_因子和表

R語言編程藝術_第六章_因子和表

女性 案例 子列 認識 改變 posit 程序實現 style 各類

一、因子與水平

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)
}

  

R語言編程藝術_第六章_因子和表