此文內容為《R語言實戰》的筆記,人民郵電出版社出版。
從高中電腦課學VB開始,大一課內開始學習C++,到後來大二為了數模學習Matlab,到大三為了搞深度學習自學Python,到研究生之初學習Stata——選擇一門語言對我來說就像是小時候玩冒險島,到10級的時候是轉戰士好還是弓箭手好一般的糾結。我查閱了很多B乎的文章,最後覺得可能R比較合適現在的我。
作為從Python轉進來R的新手,我把可能會用經常需要用到或經常需要查閱的代碼貼上來,主要是為了日後方便查找,就像「字典」一樣。推文的順序與教材不同,為了簡潔,我還會刪除一些我個人認為不太重要的章節。我還會按照自己的學習進度發布文章,請讀者見諒。
本文章僅供學習參考,請勿轉載,侵刪!
目錄第5章 高級數據管理在第4章,我們學習了R中基本的數據處理方法。在第5章,我們主要瀏覽R中的多種數學、統計和字符處理函數,了解如何自己編寫函數來實現數據處理和分析任務,並了解數據的整合和概述方法以及數據集的重塑和重構。
5.2 數值和字符處理函數R中作為數據處理基石的函數,可以分為數值函數(數學、統計、概率)和字符串處理函數。
5.2.1 數學函數R中常用的數學函數有:
== 函數 == == 描述 ==abs(x) 絕對值sqrt(x) 平方根ceiling(x) 不小於x的最小整數floor(x) 不大於x的最大整數trunc(x) 向0方向取整round(x, digits=n) 將x捨入為指定小數位數signif(x, digits=n) 將x捨入為指定的有效數字位數cos(x),sin(x),tan(x) 三角函數acos(x),asin(x),... 反三角函數cosh(x),sinh(x),... 雙曲三角函數acosh(x),... 反雙曲三角函數log(x, base=n) 對x取n為底數的對數log(x) 自然對數log10(x) 常用對數exp(x) 自然指數對數據做變換是這些函數的主要用途。這些函數作用於vector或matrix或data.frame對象會作用於每一個獨立的值,見:
V1 = c(1:10)V2 = c(11:20)M = matrix(V1, nrow = 2)D = data.frame(V1, V2)sqrt(V1)## [1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751 2.828427## [9] 3.000000 3.162278## [,1] [,2] [,3] [,4] [,5]## [1,] 1.000000 1.732051 2.236068 2.645751 3.000000## [2,] 1.414214 2.000000 2.449490 2.828427 3.162278## V1 V2## 1 1.000000 3.316625## 2 1.414214 3.464102## 3 1.732051 3.605551## 4 2.000000 3.741657## 5 2.236068 3.872983## 6 2.449490 4.000000## 7 2.645751 4.123106## 8 2.828427 4.242641## 9 3.000000 4.358899## 10 3.162278 4.4721365.2.2 統計函數常用的統計函數如表所示:
== 函數 == == 描述 ==mean(x) 平均值median(x) 中位數sd(x) 樣本標準差 (用n-1)var(x) 樣本方差 (用n-1)mad(x) 絕對中位數quantile(x, probs) 求分位數range(x) 求值域sum(x) 求和diff(x, lag=n) n階差分min(x) 最小值max(x) 最大值scale(x, 數據中心化(center=TRUE) cener=TRUE, 數據標準化(center和scale=TRUE) scale=TRUE)上面的函數一般會有na.rm選項,當na.rm=TRUE時會排除缺失值進行計算。具體請參考help(·)。
一個具體的應用是:
如果冗餘地寫,那麼有:
x <- c(1:8)n <- length(x)meanx <- sum(x)/ncss <- sum((x-meanx)^2)sdx <- sqrt(css/(n-1))meanx5.2.3 概率函數概率函數通常用來生成特徵已知的模擬數據,以及在用於編寫的統計函數中計算概率值。
在R中,概率函數形如:
其中:
d = 概率密度函數(pdf, density的d)p = 累積分布函數(cdf, 給定分位點求概率p(X<=x)的p)q = 分位數函數(quantile function的q,給定概率p求分位數數,是p的反函數)例如:
x <- pretty(c(-3,3), 50)pdf <- dnorm(x) # 概率密度函數cdf <- pnorm(x) # 累積分布函數quan <- qnorm( pretty(c(0,1), 100) ) # 分位數函數layout(matrix(c(1,2,3,3), 2, 2))plot(x, pdf, title("dnorm"))plot(x, cdf, title("pnorm"))plot(pretty(c(0,1), 100), quan, title("qnorm"))另外:
# 位於 z=1.96 左側的標準正態分布pdf下方的面積是多少(知道分位點求概率)pnorm(1.96)# 標準正態分布的0.9分位點值為多少(知道概率求分位點)qnorm(0.9750021)關於畫圖的命令會在下一篇推文介紹。
1.關於設定隨機種子
每次生成為隨機數的時候,函數都會使用一個不同的種子,因此也會產生不同的結果。你可以通過set.seed()指定某個種子,讓隨機的結果可以重現(reproducible),見:
## [1] 0.9580880 0.9346797 0.5693708 0.6829771 0.6390400## [1] 0.2776539 0.6784761 0.8737694 0.8826680 0.9218422## [1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154## [1] 0.1137034 0.6222994 0.6092747 0.6233794 0.86091542.多元正態數據
在模擬研究和蒙特卡洛方法中,你經常需要獲取來自給定均值向量和協方差的多元正態分布的數據。
MASS包中的mvrnorm()可以讓這個問題變得容易,請先安裝MASS包:
然後可以使用:
## Warning: package 'MASS' was built under R version 4.0.2options(digits = 3)set.seed(1234)mean <- c(230.7, 145.7, 3.6)sigma <- matrix(c(15360.8, 6721.2, -47.1, 6721.2, 4700.9, -16.5, -47.1, -16.5, .3), nrow = 3, ncol = 3)mydata <- mvrnorm(10, mean, sigma)mydata <- as.data.frame(mydata)names(mydata) <- c("Y", "X1", "X2")mydata## Y X1 X2## 1 74.5 90.43 4.16## 2 248.2 196.43 3.46## 3 351.0 236.71 3.15## 4 -56.3 4.26 4.62## 5 299.3 138.24 3.04## 6 291.0 179.52 2.88## 7 151.6 129.12 4.10## 8 148.4 144.53 3.54## 9 147.5 140.93 3.92## 10 161.4 9.96 3.215.2.4 字符處理函數數學和統計函數是用來處理數值型數據的,而字符處理函數可以從文本中抽取需要的數據信息。常見的字符串處理函數有:
== 函數 == == 描述 ==nchar(x) 計算x中的字符數量substr(x,start,end) 提取或替換字符串中的子串grep(pattern,x) 在x中搜索某種模式sub(pattern, 把x中pattern替換為replacement replacement, x)strsplit(x, split) 在split處分割向量x的元素paste(...,sep="") 連接字符串,分隔符為sep toupper(x) 大寫轉換tolower(x) 小寫轉換具體的函數形式請參考help文檔。
5.2.5 其他實用函數== 函數 == == 描述 ==length(x) 對象x的長度seq(from,to,by) 生成從from到to間隔為by的序列rep(x,n) 重複x序列n次cut(x,n) 將連續型變量x分割為有n個水平的因子pretty(x,n) 將連續變量x均勻劃分為n個區間cat(..., 連接...中的對象,並輸出到屏幕或file中 file="myfile", append=FALSE)使用上面的函數時,請先查看help獲取詳細信息。
另外,字符串裡面該可以使用以下轉義字符:
== 字符 == == 描述 ==\n 換行符(回車)\t 制表符(tab)\' 單引號\b 退格可以在Console輸入 ?Quotes 了解更多例如:
name <- "Bob"cat("Hello", name, "\b.\n", "Isn\'t R", "\t", "GREAT?\n")## Hello Bob .## Isn't R GREAT?在這裡,使用\b是因為cat在連接對象時,每個對象都會用空格分開。句號和最後一個單詞之間不需要空格,所以先用\b再輸入.消除不要的空格。
5.4 控制流在這裡介紹控制流,即判斷和循環結構。
5.4.1 循環結構1. for循環
用for循環重複執行語句,知道某個變量的值不在包含在序列seq中為止,語法是:
for (var in seq) {statement}例如:
for (i in 1:3) {print("Hello world!")}## [1] "Hello world!"## [1] "Hello world!"## [1] "Hello world!"2. while循環
while循環地重複執行一條語句,知道條件不為真為止,語法是:
例如:
i <- 3while (i>0) {print("Hello world"); i <- i-1}## [1] "Hello world"## [1] "Hello world"## [1] "Hello world"5.4.2 判斷結構1. if-else 結構
語法為:
if (cond) {statement}if (cond) {statement1} else {statement2}2. ifelse 結構
語法是:
ifelse(cond, statement1, statement2)如果cond為真,那麼執行statement1,否則執行statement2。例如:
ifelse(1>2, {"1更大"}, {"2更大"})如果程序的行為是二元的,或者希望input和output均為向量時,儘量使用ifelse結構
3. switch結構
語法是:
其中,...表示與expr的各種輸出值綁定的語句。看下面的代碼就一目了然了:
fellings <- c("sad", "afraid")for (i in fellings){ print( switch (i, happy = "I am glad you are happy!", afraid = "There is nothing to fear.", sad = "Cheer up!", angry = "Calm down now." ) )}## [1] "Cheer up!"## [1] "There is nothing to fear."5.4.3 用戶自編函數R最大的優點之一就是用戶可以自行添加函數。一個函數的基本結構的語法是:
myfunction <- function(arg1, arg2, ...){ statements return(object)}函數的對象只能在內部使用,返回的對象的數據類型是任意的,從標量到列表都可以。比如:
judge <- function(num1, num2){ return(ifelse(num1>num2, num1, num2))}judge(4,100)5.6 整合與重構R提供了很多方法用來整合(aggregate)和重構(reshape)數據。後面將使用在R基本安裝中的mtcars數據框:
## mpg cyl disp## Mazda RX4 21.0 6 160## Mazda RX4 Wag 21.0 6 160## Datsun 710 22.8 4 1085.6.1 數據集的轉置轉置即反轉行和列,直接使用t()就可以直接對一個矩陣或一個數據框進行轉置了。對於數據框,行名將變成列名。如果是對向量進行t()函數,那麼第一次t()會把向量變成一維矩陣,第二次t(t(·))才會轉置。例如:
M <- matrix(c(1:6), ncol=3)t(M)## [,1] [,2]## [1,] 1 2## [2,] 3 4## [3,] 5 6## Mazda RX4 Mazda RX4 Wag Datsun 710## mpg 21 21 22.8## cyl 6 6 4.0## disp 160 160 108.05.6.2 整合數據在R中使用一個或多個by和一個預先定義好的函數來摺疊(collapse)數據是比較容易的,語法是:
aggregate(x, by=list(...), FUN)其中x是待摺疊的對象;by是一個變量名組成的列表;FUN是預先定義好的用來計算描述性統計量的標量函數。
例如,我們根據氣缸數(cyl)和檔位數(gear)整合mtcars數據,並返回個數值型變量的均值:
options(digits = 3)attach(mtcars)aggdata <- aggregate(mtcars, by=list(cyl, gear), FUN=mean, na.rm=TRUE)aggdata## Group.1 Group.2 mpg cyl disp hp drat wt qsec vs am gear carb## 1 4 3 21.5 4 120 97 3.70 2.46 20.0 1.0 0.00 3 1.00## 2 6 3 19.8 6 242 108 2.92 3.34 19.8 1.0 0.00 3 1.00## 3 8 3 15.1 8 358 194 3.12 4.10 17.1 0.0 0.00 3 3.08## 4 4 4 26.9 4 103 76 4.11 2.38 19.6 1.0 0.75 4 1.50## 5 6 4 19.8 6 164 116 3.91 3.09 17.7 0.5 0.50 4 4.00## 6 4 5 28.2 4 108 102 4.10 1.83 16.8 0.5 1.00 5 2.00## 7 6 5 19.7 6 145 175 3.62 2.77 15.5 0.0 1.00 5 6.00## 8 8 5 15.4 8 326 300 3.88 3.37 14.6 0.0 1.00 5 6.00其中,Group.1表示氣缸數(4、6、8);Group.2表示檔位數(3、4、5)。這裡返回的列表表示,
平均來看,有4個氣缸,3個檔位的的車型每加侖汽油行駛英裡數(mpg)為21.5你也可以在by=list()中指定變量的名稱,比如:
options(digits = 3)attach(mtcars)## The following objects are masked from mtcars (pos = 3):## ## am, carb, cyl, disp, drat, gear, hp, mpg, qsec, vs, wtaggdata <- aggregate(mtcars, by=list(Group.cyl=cyl, Group.gears=gear), FUN=mean, na.rm=TRUE)aggdata## Group.cyl Group.gears mpg cyl disp hp drat wt qsec vs am gear carb## 1 4 3 21.5 4 120 97 3.70 2.46 20.0 1.0 0.00 3 1.00## 2 6 3 19.8 6 242 108 2.92 3.34 19.8 1.0 0.00 3 1.00## 3 8 3 15.1 8 358 194 3.12 4.10 17.1 0.0 0.00 3 3.08## 4 4 4 26.9 4 103 76 4.11 2.38 19.6 1.0 0.75 4 1.50## 5 6 4 19.8 6 164 116 3.91 3.09 17.7 0.5 0.50 4 4.00## 6 4 5 28.2 4 108 102 4.10 1.83 16.8 0.5 1.00 5 2.00## 7 6 5 19.7 6 145 175 3.62 2.77 15.5 0.0 1.00 5 6.00## 8 8 5 15.4 8 326 300 3.88 3.37 14.6 0.0 1.00 5 6.005.6.3 reshape2包reshape2包是一套重構和整合數據集的萬能工具,但用起來有點複雜。我們首先要安裝reshape2包:
install.packages("reshape2")然後用下面的例子來簡要介紹reshape2包。
ID <- c(1,1,2,2)Time <- c(1,2,1,2)X1 <- c(5,3,6,2)X2 <- c(6,5,1,4)mydata <- data.frame(ID, Time, X1, X2)mydata## ID Time X1 X2## 1 1 1 5 6## 2 1 2 3 5## 3 2 1 6 1## 4 2 2 2 41. 融合
數據集的融合是將其重構為這樣的格式:
每個測量變量獨佔一行,行中帶有唯一確定這個測量所需的標識符變量
上面的mydata可以使用下面的代碼進行重構:
## Warning: package 'reshape2' was built under R version 4.0.2md <- melt(mydata, id=c("ID", "Time"))md## ID Time variable value## 1 1 1 X1 5## 2 1 2 X1 3## 3 2 1 X1 6## 4 2 2 X1 2## 5 1 1 X2 6## 6 1 2 X2 5## 7 2 1 X2 1## 8 2 2 X2 4注意,必須指定唯一確定每個變量所需的變量(在這裡是ID和Time),而表示測量變量名的變量(X1, X2)將由程序為你自動創建。
2. 重構
使用dcast()命令重構融合後的數據,並使用你提供的一個公式和一個(可選的)用於整個數據的函數將其重構,調用的語法是:
newdata <- dcast(md, formula, fun.aggregate)在這裡,md是已經融合的數據;formula描述了想要的最後結果;fun.aggregate是數據整合函數。其中,formula的格式為
rowvar1 + rowvar2 + ... ~ colvar1 + colvar2 + ...其中,rowvar1 + rowvar2 + ...定義了行標籤,以確定各行的內容;colvar1 + colvar2 + ...則列表標籤,定義了各列的內容,比如:
dcast(md, ID+Time~variable)## ID Time X1 X2## 1 1 1 5 6## 2 1 2 3 5## 3 2 1 6 1## 4 2 2 2 4dcast(md, ID+variable~Time)## ID variable 1 2## 1 1 X1 5 3## 2 1 X2 6 5## 3 2 X1 6 2## 4 2 X2 1 4