《R語言實戰》學習筆記及代碼(第五章)

感謝Robert I.Kabacoff 著作本書,同時感謝高濤、肖楠、陳鋼編譯此書。

最近在學習《R語言實戰》,特將學習過程記錄下來,供各位朋友參考,雖說是筆記,但是90%是書中內容,另外10%是自己偶爾冒出的一點點想法的記錄和一些疑問,希望互相探討。末尾有本章的代碼清單下載地址,與各位交流,還是提倡按照書中內容把代碼一個個敲出來。

第五章  高級數據管理

本章內容

數學和統計函數

字符處理函數

循環和條件執行

自編函數

數據整合與重塑



5.1  一個數據處理難題

一個難題:

  1. 三科成績是無法比較的。
  2. 需要一種方法來確定某個學生在前述得分上百分比排名。
  3. 表示姓名的字段只有一個,需要將姓和名拆開。



5.2  數值和字符處理函數

本節將學習R中作為數據處理基石的函數,它們可分為數值(數學、統計、概率)函數和字符處理函數。



5.2.1  數學函數

書中表5-2列出了常用的數學函數和簡短的用例。(P83頁)

值得一提的是round(x, digits = n) 表示將x舍入為指定位的小數。

signif(x, digits = n)表示將x舍入為指定的有效數字位數。

對比如下

round(3.475, digits = 2)返回值為3.48。(保留兩位小數)

signif(3.475, n= = 2)返回值為3.5。(保留兩位有效數字)

表5-2中的示例將數學函數應用到了標量(單獨的數值)上。當這些函數被應用于數值向量、矩陣或者數據框時,它們會作用于其中每一個獨立的值,然后重新生成一個向量、矩陣或數據框。



5.2.2  統計函數

方差:表示點的離散程度。方差越小,離散程度越低,越接近平均值。公式表達為:
S=[ (x1-x)^2+(x2-x)^2+(x3-x)^2+……+(xn-x)^2]

標準差是方差開根號。

什么是絕對中位差、分位數、值域、滯后差分、進化中心化、標準化?

代碼清單5-1  均值和標準差的計算

x <- c(1, 2, 3, 4, 5, 6, 7, 8)

簡潔的方式

mean(x)

sd(x)

冗長的方式

n <- length(x)

meanx <- sum(x)/n

css <- sum((x - meanx)^2)

sdx <- sqrt(css / (n-1))

meanx

sdx

第二種方式中修正平方和(css)的計算過程是很有啟發性的:

(1) x等于c(1, 2, 3, 4, 5, 6, 7, 8),x的平均值等于4.5(length(x)返回了x中元素的數量):

(2) (x - meanx)從x中的每個元素中減去了4.5,結果為c(-3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5)

(3) (x - meanx)^2將(x - meanx)的每個元素求平方,結果為c(12.25, 6.25, 2.25, 0.25, 0.25, 2.25, 6.25, 12.25)

(4) summ((x - meanx)^2)對((x - meanx)^2)的所有元素求和,結果為42。

數據的標準化

將一組數據,投射到很小區間內的方法,便于分析。標準化之后的數據有這樣的特征:均值為0,標準差為1。

函數scale()對矩陣或數據框的制定了進行均值為0,標準差為1的標準化。

newdata <- scale(mydata

要對每一列進行任意均值和標準差的標準化,可以使用如下代碼:

newdata <- scale(mydata) * SD + M

其中SD表示想要的標準差,M表示想要的均值。注意,在非數值型的列上用scale()函數會報錯。如果要對指定列而不是整個數據框或矩陣進行標準化,可以使用如下代碼:

newdata <- transform(mydata, myvar = scale(myvar) * 10 + 50)

此句將變量myvar標準化為均值50、標準差為10的變量。

問:是否有能將數據落到指定區間的方法?這種方法與書中的“指定均值和標準差”的方法有何異同?



5.2.3  概率函數

概率函數通常用來生成特征已知的模擬數據,以及在用戶編寫的統計函數中計算概率值。在R中,概率函數形如:
[dpqr]distribution_abbreviation()

其中第一個字母表示其所指分布的某一方面:

d = 密度函數(density)

p = 分布函數(distribution function)

q = 分位數函數(quantile function)

r = 生成隨機數(隨機偏差)

1. 設定隨機數種子

每次生成偽隨機數的時候,函數都會使用一個不同的種子,可以通過函數set.seed()顯式指定這個種子,讓結果可以重現(reproducible)。代碼清單5-2給出了一個示例,這里的函數runif()用來生成0到1區間上服從均勻分布的偽隨機數。

設置種子之后,如果種子是同一個數,那么每次產生的隨機數,求和、均值、標準差都相同。這幾個參數與種子數之間有什么關系?

注意:如果需要設定種子,那么在每一次生成隨機數之前都要設定

2. 生成多元正態數據

蒙特卡洛方法:也稱統計模擬方法,是以概率統計理論為指導的一類非常重要的數值計算方法。是指使用隨機數(或更常見的偽隨機數)來解決很多計算問題的方法。與它對應的是確定性算法。蒙特卡洛方法百度百科解釋

MASS包可以讓獲取來自給定均值向量和協方差陣的多元正態分布的數據變得更容易。調用格式為:

mvrnorm(n, mean, sigma)

其中n是你想要的樣本大小,mean為均值向量,而sigma是方差-協方差矩陣(或相關矩陣)。



5.2.4  字符處理函數

書中P89-P90頁,表5-6 給出了字符處理函數表。

請注意,函數grep()、sub()和strsplit()能夠搜索某個文本字符串(fixed = TRUE)或者某個正則表達式(fixed = FALSE,默認值為FALSE)。正則表達式為文本模式的匹配提供了一套清晰而簡練的語法。正則表達式 - 語法或者正則表達式語法。

例如^[hc]?at

可以匹配任意0個或1個以h或c開頭、后接at的字符串。因此,此表達式可以匹配hat、cat和at,但不會匹配bat。



5.2.5  其他實用函數

轉義符“\”,\n表示新行,\t為制表符,'為單引號,\b為退格。



5.2.6  將函數應用于矩陣和數據框

R函數的諸多有趣特性之一就是他們可以應用到一系列的數據對象上,包括向量、標量、矩陣、數組和數據框。

R中提供了一個apply()函數,可將一個任意函數“應用”到矩陣、數組、數據框的任何維度上。其格式為:

apply(x, MARDIN, FUN, …)

其中,x為數據對象,MARGIN是維度的下標,FUN是由你指定的函數,而…則包含了想傳遞給FUN的參數。在矩陣或數據框中,MARGIN=1表示行,MARGIN=2表示列。

mydata <- matrix(rnorm(30), nrow = 6)

mydata

apply(mydata, 1, mean)

apply(mydata, 2, mean)

apply(mydata, 2, mean, trim =0.2)

最后一行表示計算每一列的截尾均值,忽略了最高和最低的20%。

apply()可把函數應用到數組的某個維度上,而lapply()和aspply()則可將函數應用到列表(list)上。



5.3  數據處理難題的一套解決方案

針對5.1節提出的問題,本節給出了一個解決方案。

  1. options(digits = 2)
  2. Student <- c("John Davis", "Angela Williams", "Bullwinkle Moose", "David Jones", "Janice Markhammer", "Cheryl Cushing", "Reuven Ytzrhak", "Greg Knox", "Joel England","Mary Rayburn")
  3. Math <- c(502, 600, 412, 358, 495, 512, 410, 625, 573, 522)
  4. Science <- c(95, 99, 80, 82, 75, 85, 80, 95, 89, 86)
  5. English <- c(25, 22, 18, 15, 20, 28, 15, 30, 37, 18)
  6. roster <- data.frame(Student, Math, Science, English, stringsAsFactors = FALSE)
  7. z <- scale(roster[ , 2:4])
  8. score <- apply(z, 1, mean)
  9. roster <- cbind(roster, score)
  10. y <- quantile(score, c(0.8, 0.6, 0.4, 0.2))
  11. y
  12. roster$grade[score >= y[1]] <- "A"
  13. roster$grade[score < y[1] & score >= y[2]] <- "B"
  14. roster$grade[score < y[2] & score >= y[3]] <- "C"
  15. roster$grade[score < y[3] & score >= y[4]] <- "D"
  16. roster$grade[score < y[4]] <- "F"
  17. name <- strsplit((roster$Student), " ")
  18. name
  19. lastname <- sapply(name, "[", 2)
  20. firstname <- sapply(name, "[", 1)
  21. roster <- cbind(firstname, lastname, roster[, -1])
  22. roster <- roster[order(lastname, firstname),]
  23. roster

以下是解讀過程:

  1. 限定了輸出小數點后數字的位數,并且讓輸出更容易閱讀。

  2. 輸入學生姓名。

  3. 輸入數學成績。

  4. 輸入科學成績。

  5. 輸入英語成績。

  6. 創建一個數據框roster,其中的變量分別是:姓名、數學成績、科學成績、英語成績。

  7. 將數據框roster的第二到四列標準化,并保存到z中。標準化的原因是:由于數學、科學、和英語考試得到分值不同(均值和標準差相去甚遠),在組合之前需要讓他們變得可以比較。標準化就是讓每科的成績都用單位標準差來表示,而不是以原始的尺度來表示了。

  8. 求z中所有行的均值,并保存到score中。

  9. 將roster和score按列合成為一個矩陣,保存到roster中。

  10. 分別求score的20%分位數,40%分位數,60%分位數,80%分位數。

  11. 查看score的20%分位數,40%分位數,60%分位數,80%分位數。分別是
    80% : 0.91
    60% : 0.32
    40% : -0.36
    20% : -0.88

  1. 將大于等于80%,即大于等于0.91的成績評為A。

  2. 將60%(包含)至80%(不包含),即位于0.32(包含)和0.91(不包含)之間的成績,評為B。

  3. 將40%(包含)至60%(不包含),即位于-0.36(包含)和0.32(不包含)之間的成績,評為C。

  4. 將20%(包含)至40%(不包含),即位于-0.88(包含)和-0.36(不包含)之間的成績,評為D。

  5. 將小于20%,即小于-0.88的成績評為F。

  6. 使用strsplit()函數,將原數據框中的姓名,按照空格分成兩列,并保存到新的列表name中。

  7. 查看新列表name。

  8. 選取列表中第二列,保存到一個新變量lastname中。

  9. 選取列表中第一列,保存到一個新變量firstname中。

  10. 將firstname和lastname添加到花名冊roster中,并將原本第一個變量Student刪除,(roster[, -1])。

  11. 使用order()函數依照firstname和lastname對數據框進行排序。

  12. 查看數據框roster。



5.4  控制流

為了理解貫穿本節的語法示例,請牢記以下概念:

語句(statement)是一條單獨的R語句或一組符合語句(包含在花括號{}中的一組R語句,使用分號分隔);

條件(cond)是一條最終被解析為真(TRUE)或假(FALSE)得表達式;

表達式(expr)是一條數值或字符串的求值語句;

序列(seq)是一個數值或字符串序列。



5.4.1  重復和循環

循環結構重復地執行一個或一系列語句,知道某個條件不為真為止。循環結構包括for和while結構。

1.  for結構

for循環重復地執行一個語句,直到某個變量不包不再包含在序列seq中為止。語法為:

for(var in seq) statement

在下例中:

for (i in 1:10) print ("Hello")

單詞Hello被輸出了10次。

2.  while結構

while循環重復地執行一個語句,直到條件不為真為止。語法為“

while (cond) statement

第二個例子,代碼:

i <- 10

while (i < 0) {pirnt ("Hello"); i <- i - 1}

請確保括號內while的條件語句能夠改變,即讓它在某個時刻不再為真——否則循環將永不停止!



5.4.2  條件執行

在條件執行結構中,一條或一組語句僅在滿足一個指定條件時執行。條件執行結構包括if-else、ifelse和switch。

1.  if-else結構

控制結構if-else在某個給定條件為真時執行語句。也可以同時在條件為假時執行另外的語句,語法為:

if (cond) statement

if (cond) statement1 else statement2

示例如下:

if (is.character(grade)) grede <- as.factor(grade)

當grade為字符型向量時,將其轉化為因子。

if (!is.factor(grade)) grade <- as.factor else print ("Grade already is a factor")

當grade不是因子時,將其轉化為因子,當其是因子是,輸出一段信息。

2.  ifelse結構

ifelse是if-else比較緊湊的向量化結構。語法為:

ifelse (cond, statement1, statement2)

當條件為真時,執行第一條語句,當條件為假時,執行第二條語句。

示例如下:

ifelse (score > 0.5, print("Passed"), print("Failed"))

outcome <- ifels (score > 0.5, "Passed", "Failed")

3.  switch結構

switch根據一個表達式的值選擇語句執行。語法如下:

switch(expr, …)

其中的…表示與expr的各種可能輸出值綁定的語句。



5.5  用戶自編函數

R最大的優點之一就是用戶可以自行添加函數。R中許多函數都是由已有函數構成的。一個函數的結構看起來大致如此:

myfunction <- function(arg1, arg2, …){

  statements

  return(object)

  }

在第二個自編函數的示例中,函數cat()僅會在輸入的日期格式類型不匹配“long”或“short”時執行。使用一個表達式來捕獲錯誤輸入的參數值通常是一個好主意

有若干函數可以用來為函數添加錯誤捕獲和糾正功能。warning()可以生成一條錯誤提示信息。message()可以生成一條診斷信息。stop()可以停止當前表達式的執行并提示錯誤。

小提示

一旦開始編寫無論任何長度和復雜度的函數,優秀調試工具的重要性都會凸顯出來。R中有許多實用的內建調試函數,也有許多用戶貢獻包提供了額外的功能。

關于這個話題,一份優秀的參考資料是Duncan Murdoch整理的“Debugging in R”。



5.6  整合與重構

在整合數據時,往往將多組觀測替換為根據這些觀測計算的描述性統計量。在重塑數據時,則會通過修改數據的結構(行和列)來決定數據的組織方式。



5.6.1  轉置

轉置(反轉行和列)也許是重塑數據集的眾多方法種最簡單的一個了。使用函數t()即可對一個矩陣或者數據框進行轉置。對于后者,行名將成為變量(列)名。



5.6.2  整合數據

在R中使用一個或多個by變量和一個預先定義好的函數來折疊(collapse)數據時比較容易得多。其調用格式為:

aggregate(x, by, FUN)

其中x是待折疊的數據對象,by是一個變量名組成的列表,這些變量將被去掉以形成新的觀測,而FUN則是用來計算描述性統計量的標量函數,它將用來計算新觀測中的值。

5.6.3  reshape包

首先將數據“融合”(melt),以使每一行都是一個唯一的標識符-變量組合。然后將數據“重鑄”為你想要的任何形狀。在重鑄過程中你可以使用任何函數對數據進行整合。

在這個數據集中,測量(measurement)是指最后兩列中的值(5、6、3、5、6、1、2、4)。每個測量都能夠被標識符(在本例中,標識符是指ID、Time以及觀測屬于X1還是X2)唯一地確定。

1.  融合

使用以下代碼:

install.package("reshape")

library(reshape)

md <- melt(mydata, id = (c("id", "time")))

2.  重鑄

cast()函數讀取已融合的數據,并使用你提供的公式和一個(可選的)用于整合數據的函數將其重塑。調用格式為:

newdata <- cast(md, formula, FUN)

其中的md為已融合的數據,formula描述了想要的最后結果,而FUN是(可選的)數據整合函數。其接受公式形如:

rowvar1 + rowvar2 + … + ~ colvar1 + colvar2 + …

在這一公式中,rowvar1 + rowvar2 + … 定義了要劃掉的變量集合,以確定各行的內容,而colvar1 + colvar2 + … 則定義了要劃掉的、確定各列內容的變量集合。





<font color=gray size=3 face="微軟雅黑">作者注:本節(5.6.3)由于第一個示例代碼就無法得到書中的結果,所以,本節學習筆記實際上只摘取了書中的內容,未理解其中的意義。主要是由于示例的表5-8 不知道何種形式的數據集,書中未給出,在嘗試了矩陣、數據框、列表創建相同內容的數據集之后,均失敗。</font>

附件:《R語言實戰》學習筆記及代碼(第五章)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容