最近在學(xué)習(xí)R凯砍,主要在看《R語言入門與實(shí)踐》這本書(Garrett Grolemund著,馮凌秉譯拴竹,人民郵電出版社)悟衩,做了一些筆記,分享給大家
目錄
這篇筆記的PDF版本:https://pan.baidu.com/s/1PB874TCKAWOP65TM6euFPg
提取碼:08kx
第一部分
第一章 R基礎(chǔ)
1.1 下載栓拜、安裝R和RStudio
- R下載地址:https://cran.r-project.org/mirrors.html
- 選擇對(duì)應(yīng)操作系統(tǒng)的版本座泳,下載并安裝即可
- 安裝成功后的運(yùn)行效果:
- RStudio下載地址:https://rstudio.com/products/rstudio/download/#download
- 安裝成功后,運(yùn)行的效果:
1.2 將R當(dāng)成一個(gè)計(jì)算器
- 可以在R中進(jìn)行各種數(shù)學(xué)運(yùn)算幕与,例如:
> 5*(7^2+1)-3
[1] 247
- 優(yōu)先級(jí):冪運(yùn)算 > 乘除運(yùn)算 > 加減運(yùn)算
- 括號(hào)內(nèi)的運(yùn)算將優(yōu)先進(jìn)行挑势,存在多個(gè)括號(hào)時(shí),優(yōu)先計(jì)算最內(nèi)層的括號(hào)
1.3 對(duì)象
- 我們可以使用賦值符號(hào)
<-
(=
也可以纽门,不過更推薦<-
)將數(shù)值儲(chǔ)存在一個(gè)對(duì)象中薛耻,例如:
> a <- 5*(7^2+1)-3
> a
[1] 247
- 對(duì)象名不能以數(shù)字或一些特殊字符開頭
- 對(duì)象名區(qū)分大小寫,例如name和Name是不同的對(duì)象
- 如果把新的內(nèi)容賦值給一個(gè)已存在的變量赏陵,則將會(huì)覆蓋掉變量的原始值
- 使用
ls()
查看已經(jīng)命名的對(duì)象饼齿,使用rm(對(duì)象名)
來刪除某個(gè)對(duì)象 - 【注意】僅輸入
rm()
會(huì)刪除所有對(duì)象,慎用蝙搔!
1.4 函數(shù)
- R中存在各種各樣功能強(qiáng)大的函數(shù)缕溉,即執(zhí)行某種任務(wù)的語句。例如吃型,mean函數(shù)的作用是計(jì)算算術(shù)平均值证鸥,round函數(shù)的作用是四舍五入,sample函數(shù)的作用是從一個(gè)向量中抽取size個(gè)元素并返回,如下:
> mean(1:6)
[1] 3.5
> round(mean(1:6))
[1] 4
> sample(1:6,size=2)
[1] 5 3
- 正如上述例子中的
round(mean(1:6))
所展示的枉层,函數(shù)可以嵌套 - 通過args函數(shù)查看函數(shù)的參數(shù)泉褐,例如:
> args(sample)
function (x, size, replace = FALSE, prob = NULL)
NULL
- 我們可以根據(jù)需要,自己編寫自定義函數(shù)鸟蜡,例如下面是一個(gè)計(jì)算t檢驗(yàn)效應(yīng)量的函數(shù)
> #自定義函數(shù):計(jì)算t檢驗(yàn)的效應(yīng)量
> conhens_d <- function(m1, m2, s) {
+ d <- (m1-m2)/s
+ return(d)
+ }
> #調(diào)用自定義函數(shù)
> conhens_d(23,21,2.5)
[1] 0.8
- 一些相關(guān)的信息:
-
conhens_d
是函數(shù)名 -
m1
膜赃、m2
、s
是函數(shù)中的參數(shù)揉忘,只在函數(shù)內(nèi)部有效跳座,如果想設(shè)置默認(rèn)值,則可以在參數(shù)后面添加等號(hào)和數(shù)值泣矛,例如m1=23
- 花括號(hào)中的代碼是函數(shù)的主體
- 通過
return()
返回值 -
#
是注釋符疲眷,以#
開頭的代碼不會(huì)運(yùn)行 - 如果指令太長,對(duì)于一條明顯未完整的指令您朽,敲一下回車鍵狂丝,就可以換行(會(huì)顯示一個(gè)“+”,提示用戶繼續(xù)輸入)
-
1.5 腳本
- 將代碼寫在腳本文件中虚倒,隨后我們可以保存該文件美侦,以便將來使用,在RStudio中的腳本窗口存在兩個(gè)運(yùn)行腳本的按鈕:
- Source:運(yùn)行腳本中的全部代碼魂奥,對(duì)應(yīng)的語句是
source('腳本名.R')
(另一種方法是Ctrl+A然后Ctrl+Enter) - Run:運(yùn)行腳本中的某一行(快捷鍵Crtl+Enter)
- Source:運(yùn)行腳本中的全部代碼魂奥,對(duì)應(yīng)的語句是
第二章 R包與幫助系統(tǒng)
2.1 R包
- 許多大學(xué)教授菠剩、程序員和統(tǒng)計(jì)學(xué)家使用R設(shè)計(jì)了數(shù)據(jù)分析的工具,并將這些工具無償提供給他人使用耻煤,這些工具就屬于R包具壮。
- R包類似于C、C++和JavaScript中的庫(library)哈蝇,或者Python中的包(package)
- 例如棺妓,ggplot2是一個(gè)很受歡迎的可視化包,為了使用這個(gè)包炮赦,我們首先需要確保計(jì)算機(jī)已經(jīng)連接互聯(lián)網(wǎng)怜跑,并在RStudio中的命令行輸入
install.packages()
命令來安裝包
install.packages('ggplot2')
- 但該步驟只是將ggplot2安裝到我們的計(jì)算機(jī)中,想要使用這個(gè)包的函數(shù)吠勘,首先需要加載這個(gè)包
library('ggplot2')
- 現(xiàn)在性芬,試著輸入
qplot
,這是ggplot2包中的一個(gè)函數(shù)剧防,輸入后將會(huì)顯示該函數(shù)的源代碼
> qplot
function (x, y, ..., data, facets = NULL, margins = FALSE, geom = "auto",
xlim = c(NA, NA), ylim = c(NA, NA), log = "", main = NULL,
xlab = NULL, ylab = NULL, asp = NA, stat = NULL, position = NULL)
{
...
}
如果未使用library函數(shù)導(dǎo)入ggplot2包便直接輸入
qplot
植锉,結(jié)果會(huì)顯示錯(cuò)誤: 找不到對(duì)象'gplot'
,這是因?yàn)楸仨氁d入一個(gè)包才能使用其中的函數(shù)現(xiàn)在試著輸入如下的代碼峭拘,體驗(yàn)一下
qplot
的功能吧
> x <- c(-1,-.8,-.6,-.4,-.2,0,.2,.4,.6,.8,1)
> y <- x^3
> qplot(x,y)
-
qplot
的含義是“quick plot”俊庇,其作用是依據(jù)兩個(gè)相同長度的向量來繪制散點(diǎn)圖狮暑,對(duì)于上述的例子,結(jié)果如下
- 如果想更新R包辉饱,則可以使用
update.packages()
命令搬男,如果想同時(shí)更新多個(gè)R包,只需要把R包名稱放入到一個(gè)向量中(第二章會(huì)介紹什么是向量)鞋囊,例如:
update.packages(c('ggplot2','reshape2','dplyr'))
- 如果想同時(shí)安裝多個(gè)R包止后,也可以使用這樣的方法
2.2 從幫助頁面獲取幫助
R的函數(shù)非常多,想要記住和學(xué)會(huì)所有函數(shù)幾乎是不可能的溜腐,所幸每個(gè)R函數(shù)都有自己的幫助頁面,在RStudio中輸入
?函數(shù)名
即可打開相應(yīng)的頁面例如:
?qplot
- 此時(shí)將打開該函數(shù)的幫助頁面(點(diǎn)擊下圖所示的按鈕可以打開單獨(dú)的頁面)
- 一般來說瓜喇,幫助頁面包含了以下信息
簡介 | |
---|---|
描述(Description) | 一段簡短的有關(guān)該函數(shù)功能的描述 |
用法(Usage) | 告訴我們?nèi)绾捂I入該函數(shù)和相應(yīng)的參數(shù)名 |
參數(shù)(Arguments) | 列出該函數(shù)所包含的所有參數(shù)挺益、各參數(shù)接受的賦值類型以及參數(shù)的作用 |
相關(guān)細(xì)節(jié)(Details) | 對(duì)函數(shù)的工作原理的進(jìn)一步描述,通常會(huì)提到一些使用函數(shù)時(shí)的注意事項(xiàng) |
返回值(Value) | 一段關(guān)于該函數(shù)運(yùn)行后的返回值的簡短描述 |
另請(qǐng)參閱(See also) | 與該函數(shù)相關(guān)的函數(shù)的列表 |
示例(Examples) | 確背撕可以無錯(cuò)運(yùn)行的代碼示例 |
- 此外望众,如果我們不小心忘記了某個(gè)函數(shù)的確切名稱,可以使用
??函數(shù)名的關(guān)鍵詞
來查找相關(guān)的函數(shù)伞辛,例如可以輸入以下代碼烂翰,查看與“plot”相關(guān)的函數(shù)
??plot
2.3 獲取更多的幫助
- Stack Overflow(https://stackoverflow.com/)是一個(gè)非常流行的技術(shù)問答網(wǎng)站,可以在這里搜索和上傳你遇到的問題
第二部分
第三章 R對(duì)象
3.1 原子型向量
- 原子型向量是R中最基本的數(shù)據(jù)類型蚤氏,是一系列數(shù)值的集合
- 使用
c()
將數(shù)值或字符串合并為一個(gè)原子型向量甘耿,(c的意思是concatenate,也可以理解為collect竿滨、combine)
> x <- c(3,-2,4,7,5,-1,0)
> x
[1] 3 -2 4 7 5 -1 0
- 使用
is.vector()
查看某個(gè)對(duì)象是否是向量 - 使用
length()
獲取向量的長度
> is.vector(x)
[1] TRUE
> length(x)
[1] 7
-
向量也支持計(jì)算:
- 當(dāng)對(duì)象y的值為4時(shí)佳恬,
x+y
意味著x中每個(gè)元素加4 - 當(dāng)y也是向量時(shí),
x+y
意味著對(duì)應(yīng)索引的元素相加
- 當(dāng)對(duì)象y的值為4時(shí)佳恬,
原子型向量的6種基本類型:
簡介 | |
---|---|
double(雙整數(shù)型) | 也稱為數(shù)值型(numeric)于游,這個(gè)是R中默認(rèn)的向量類型毁葱,例如上述例子中的向量x就屬于double |
integer(整數(shù)型) | 儲(chǔ)存整數(shù)數(shù)值,定義方法:在數(shù)值后加一個(gè)大寫的L贰剥,例如y=c(1L, 2L, 3L) 倾剿,integer可以避免在double中可能出現(xiàn)的浮點(diǎn)誤差問題(例如sqrt(2)^2-2 的輸出結(jié)果不為0) |
character(字符型) | 儲(chǔ)存文本,也稱字符串(string)蚌成,定義方法:添加單引號(hào)或雙引號(hào)前痘,例如text=c('hello','world') 。字符串也可以是數(shù)字笑陈,例如text=c('1','2','3') 际度,但character向量無法進(jìn)行四則運(yùn)算 |
logical(邏輯型) | 定義方法:大寫的TRUE和FALSE,例如logic=c(TRUE, FALSE, TRUE)
|
complex(復(fù)數(shù)類型)和raw(原始類型) | conplex向量用于儲(chǔ)存復(fù)數(shù)涵妥,raw向量用于儲(chǔ)存數(shù)據(jù)的原始字節(jié) |
- 可以使用
typeof()
命令查看向量的類型 - 向量的常見屬性有name(名稱)乖菱、dim(維度)和class(類)坡锡。例如,對(duì)于上述例子中的向量x窒所,我們可以通過
names()
添加名稱:
> x <- c(3,-2,4,7,5,-1,0)
> names(x) <- c('one','two','three','four','five','six','seven')
> x
one two three four five six seven
3 -2 4 7 5 -1 0
- 使用
:
來快速定義向量
> x <- 1:6
> x
[1] 1 2 3 4 5 6
- 可以在這個(gè)方法的基礎(chǔ)上靈活變通鹉勒,例如,如果想要小數(shù)的話:
> x <- (1:6)*0.3
> x
[1] 0.3 0.6 0.9 1.2 1.5 1.8
3.2 矩陣
- 矩陣將數(shù)值儲(chǔ)存在一個(gè)二維數(shù)組中吵取,我們可以使用matrix函數(shù)將向量放置在矩陣中禽额,并通過參數(shù)
nrow
、ncol
來設(shè)置矩陣的行皮官、列的數(shù)量脯倒,例如:
> a <- c(1,2,3,4,5,6)
> m <- matrix(a,nrow=2,ncol=3)
> m
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
3.3 數(shù)組
- 使用array函數(shù)來生成一個(gè)n維的數(shù)組,通過
dim
參數(shù)來設(shè)置維度大小
> a <- array(c(1:24), dim=c(2,3,4))
> a
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
, , 3
[,1] [,2] [,3]
[1,] 13 15 17
[2,] 14 16 18
, , 4
[,1] [,2] [,3]
[1,] 19 21 23
[2,] 20 22 24
3.4 類
- 使用class函數(shù)來查看對(duì)象的類捺氢,即class屬性(class和type不是一個(gè)東西)藻丢,例如,對(duì)于上述的數(shù)組a:
> class(a)
[1] "array"
- R使用了一個(gè)特殊的類來表述時(shí)間和日期數(shù)據(jù)
> now <- Sys.time()
> now
[1] "2020-11-03 20:35:47 CST"
> typeof(now)
[1] "double"
> class(now)
[1] "POSIXct" "POSIXt"
- 因子(factor)這個(gè)類儲(chǔ)存的是分類數(shù)據(jù)摄乒,例如:
> gender <- factor(c('male','female','female'))
> attributes(gender)
$levels
[1] "female" "male"
$class
[1] "factor"
- factor函數(shù)使得在統(tǒng)計(jì)分析中加入分類變量變得簡單悠反,R時(shí)常會(huì)嘗試將character向量轉(zhuǎn)換成factor,除非有這樣的需要馍佑,否則一般應(yīng)該避免這種強(qiáng)制轉(zhuǎn)換(使用
as.character()
函數(shù))
3.5 強(qiáng)制轉(zhuǎn)換
- 如果把不同類型的數(shù)據(jù)放入同一個(gè)對(duì)象中斋否,R會(huì)將其強(qiáng)制轉(zhuǎn)換為同一類型的數(shù)據(jù)(例如,將字符串和數(shù)字放入一個(gè)向量中拭荤,數(shù)字會(huì)被轉(zhuǎn)變?yōu)樽址还螅瑢?shù)字和邏輯型放入一個(gè)向量中卵牍,TRUE會(huì)被轉(zhuǎn)換為1,F(xiàn)ALSE會(huì)被轉(zhuǎn)換為0)
- 可以使用as函數(shù)家族進(jìn)行強(qiáng)制轉(zhuǎn)換,例如:
> as.character(1)
[1] "1"
> as.logical(1)
[1] TRUE
> as.double(TRUE)
[1] 1
3.6 列表
- 列表(list)儲(chǔ)存的是對(duì)象而非數(shù)值区匠,通過列表苛蒲,我們可以將不同類型的數(shù)據(jù)(數(shù)字啦帆喇、字符串啦钓简、邏輯型啦)放置在一個(gè)集合里
> my_list <- list(1:10, 'text', TRUE)
> my_list
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] "text"
[[3]]
[1] TRUE
3.7 數(shù)據(jù)框
- 數(shù)據(jù)框(data frame)是列表的二維版本。在數(shù)據(jù)框中评凝,每一列是一個(gè)向量(和Excel表格比較相似)追葡,并且各個(gè)向量的長度要相等,例如:
> students <- data.frame(name=c('harry','ron','hermione'), gender=c('male','male','female'),age=c(17,17,17))
> students
name gender age
1 harry male 17
2 ron male 17
3 hermione female 17
- 數(shù)據(jù)框其實(shí)是一個(gè)class為data.frame的列表
- 上述的name和gender實(shí)際上將被存儲(chǔ)為factor奕短,如果不想被強(qiáng)制轉(zhuǎn)換宜肉,可以在
data.frame()
中添加一個(gè)參數(shù)stringsAsFactors=FALSE
- 數(shù)據(jù)框的索引方法:數(shù)據(jù)框名稱+美元符號(hào)+列的名稱,例如
students$gender
可以返回students
這個(gè)數(shù)據(jù)框中名為gender
的一列(非常方便t岜)
> students$gender
[1] "male" "male" "female"
- 2021/3/29更新:我發(fā)現(xiàn)data.table比data.frame更好用谬返,推薦大家嘗試(需要先安裝“data.table”包)
3.8 加載和保存數(shù)據(jù)
3.8.1 R基礎(chǔ)包中的數(shù)據(jù)集
- R中的基礎(chǔ)包datasets自帶了很多數(shù)據(jù)集,這些數(shù)據(jù)集沒有太多的分析價(jià)值日杈,主要的作用是方便我們測試代碼遣铝∮铀ⅲ可以使用以下命令來查看這些數(shù)據(jù)集的簡介:
help(packages='datasets')
- 若想使用某個(gè)數(shù)據(jù)集,酿炸,只需要輸入其名稱即可(見第十章的筆記)
3.8.2 工作目錄
當(dāng)嘗試加載或保存數(shù)據(jù)時(shí)瘫絮,在沒有額外指定文件地址的情況下,R都會(huì)在一個(gè)默認(rèn)的文件目錄中進(jìn)行操作填硕,這就是R的工作目錄
可以使用如下代碼查看R的工作目錄:
> getwd()
[1] "C:\Users\韋子謙\Documents"
- 對(duì)于不同的計(jì)算機(jī)麦萤,默認(rèn)的工作目錄可能是不同的。以及扁眯,R無法讀取中文路徑的文件(至少在我自己的電腦上是這樣的)壮莹,最好將工作目錄設(shè)置為其他的位置。改變工作目錄的方法之一是setwd函數(shù)
> setwd('D:/R_project')
- 但我自己嘗試的結(jié)果是姻檀,每次啟動(dòng)RStudio垛孔,之前用
setwd()
函數(shù)設(shè)置的工作目錄就會(huì)失效,解決的方法是直接在RStudio的菜單欄里修改工作目錄:“Tools”——“Globe Options”——“Gneral”——“Basic”——“R Sessions”——“Default working directory (when not in a project)”
3.8.3 讀取和寫入純文本文件
純文本文件是存儲(chǔ)數(shù)據(jù)的常見格式之一施敢,其將數(shù)據(jù)表存儲(chǔ)在了文本文件中,表中每一行都對(duì)應(yīng)文本中的一行狭莱,每一行的不同元素都用一些簡單的符號(hào)隔開僵娃,即分隔符
常用的分隔符有空格、逗號(hào)腋妙,等等默怨。每個(gè)文件只會(huì)使用其中一種分隔符
所有的純文本文件都可以存儲(chǔ)為擴(kuò)展名為txt的文件,但有時(shí)候也可以使用特殊的擴(kuò)展名以告訴用戶該文件使用的分隔符骤素。例如匙睹,csv(Comma-Separated Values)格式的文件使用逗號(hào)作為分隔符
要加載一個(gè)純文本文件,可以使用read函數(shù)济竹,舉個(gè)例子:
data1 <- read.table('data.csv',sep=',',header=TRUE,na.strings='.',skip=3,nrow=5,stringsAsFactors=FALSE)
-
在這里痕檬,我們從R的工作目錄加載了一個(gè)名為“data.csv”的數(shù)據(jù)集,并將其內(nèi)容放置在名為
data1
的對(duì)象中送浊,涉及到的參數(shù)如下:- sep:該參數(shù)告訴
read.table()
我們的文件使用了何種分隔符 - header:是否將第一行的數(shù)據(jù)視為變量名梦谜。如果第一行是變量名,則設(shè)置為TRUE
- na.strings:有時(shí)候袭景,數(shù)據(jù)文件中會(huì)使用一些符號(hào)來表示缺失值(NA)唁桩,該參數(shù)會(huì)告訴
read.table()
缺失值的位置,read.table()
則會(huì)將這些值讀取為NA(在上面這個(gè)例子中耸棒,數(shù)據(jù)文件中用于表示缺失值的符號(hào)為“.”) - skip:有時(shí)也我們需要忽略數(shù)據(jù)文件開頭的幾行荒澡,此時(shí)可以用skip來指定從第幾行開始讀取數(shù)據(jù)
- nrow:告訴
read.table()
在讀取了一定數(shù)量的數(shù)據(jù)行后就不再讀取(指定的行數(shù)不包括表頭) - stringsAsFactors:有時(shí)候R會(huì)將字符串類型轉(zhuǎn)換為因子型与殃,如果不想讓R這么做单山,則可以將stringsAsFactors設(shè)置為FALSE
- sep:該參數(shù)告訴
當(dāng)需要加載多個(gè)數(shù)據(jù)時(shí)碍现,還可以通過更改全局設(shè)置來統(tǒng)一設(shè)定一些參數(shù),例如:
options(stringsAsFactors=FALSE)
- read函數(shù)家族
默認(rèn)設(shè)置 | 使用情形 | |
---|---|---|
read.table | sep=" ", header=FALSE | 通用讀取函數(shù) |
read.csv | sep=",", header=TRUE | 逗號(hào)分隔值(csv)的文件 |
read.delim | sep="\t", header=TRUE | 制表符分隔的文件(制表符就是Tab鍵敲出的那個(gè)符號(hào)饥侵,相當(dāng)于縮進(jìn)) |
read.csv2 | sep=";", header=TRUE, dec="," | 歐式小數(shù)點(diǎn)符號(hào)的csv文件 |
read.delim2 | sep="\t", header=TRUE, dec="," | 歐式小數(shù)點(diǎn)符號(hào)的制表符分隔的文件 |
- 在RStudio中鸵赫,通過點(diǎn)擊Environment面板的“import Dataset”,也可以將外部文檔的數(shù)據(jù)導(dǎo)入至數(shù)據(jù)框中(該功能相當(dāng)于
read.table()
命令的圖形用戶界面)
- 使用write函數(shù)保存數(shù)據(jù)躏升,如下:
文件格式 | 函數(shù)及其使用方法 |
---|---|
csv | write.csv(r_object, file=filepath, row.names=FALSE) |
歐式小數(shù)點(diǎn)符號(hào)的csv | write.csv2(r_object, file=filepath, row.names=FALSE) |
制表符分隔 | write.table(r_object, file=filepath, sep="\t", row.names=FALSE) |
- 需要注意的是辩棒,write函數(shù)無法在計(jì)算機(jī)上創(chuàng)建新的文件夾,因此在保存文件時(shí)膨疏,請(qǐng)確保寫入路徑的文件夾都已創(chuàng)建好
- 此外一睁,還可以使用bzfile(bzip2類型)、gzfile(gzip類型)或xzfile函數(shù)(xz類型)來壓縮文件佃却,用法如下:
write.csv(data1, file=bzfile("data1.csv.bz2"), row.names=FALSE)
- 讀取壓縮文件的方法如下:
read.csv("data1.csv.bz2")
3.8.4 讀取和寫入R文件
RDS文件可以存儲(chǔ)單個(gè)R對(duì)象者吁,而RData文件可以存儲(chǔ)多個(gè)R對(duì)象
使用readRDS函數(shù)來打開RDS文件,例如:
data1 <- readRDS("data1.RDS")
- 打開RData的方法則更簡單饲帅,只需運(yùn)行l(wèi)oad函數(shù)即可复凳,其中的R對(duì)象會(huì)以其原本的名稱加載到工作區(qū)中:
load("data1.RData")
【tips】RData不會(huì)告訴你讀取了多少個(gè)R對(duì)象,也不會(huì)告訴你各個(gè)對(duì)象的具體名稱灶泵,解決的方法之一是在命令行兩側(cè)加上括號(hào)育八,例如
(load("data1.RData"))
,這會(huì)強(qiáng)制R在讀取文件時(shí)顯示其中所有對(duì)象的名稱將對(duì)象保存RDS文件的方法是saveRDS函數(shù)赦邻,第一個(gè)參數(shù)是R對(duì)象的名稱髓棋,第二個(gè)參數(shù)是目標(biāo)路徑和文件名。保存為RData的方法是save函數(shù)惶洲,例如可以通過以下代碼來保存a按声、b、c三個(gè)對(duì)象:
save(a,b,c,file="data1.RData")
- RData的缺點(diǎn)在于恬吕,我們可能自己都忘了里面保存了啥東西签则,而且如果當(dāng)前的工作區(qū)存在同名對(duì)象的話,讀取RData會(huì)導(dǎo)致同名對(duì)象被覆蓋币呵,因此保存為RDS文件會(huì)更好一些
- 相比存儲(chǔ)為純文本文件怀愧,存儲(chǔ)為R文件的好處在于,因子余赢、日期芯义、時(shí)間或類屬性等信息將得到保留,缺點(diǎn)則是妻柒,許多軟件程序都無法讀取R文件扛拨,因此其不利于數(shù)據(jù)分享,而且萬一哪天你的電腦上沒有了R举塔,那么可能連打開R文件都會(huì)變得困難(我的理解是绑警,如果你的數(shù)據(jù)還沒分析完求泰,那么可以保存為R文件以便下次繼續(xù)分析,但如果數(shù)據(jù)已經(jīng)處理好了计盒,那么最終導(dǎo)出的結(jié)果最好是純文本文件)
3.8.5 讀取Excel
- 書中介紹的方法是XLConnect包渴频,不過我發(fā)現(xiàn)目前RStudio默認(rèn)使用的是readxl包(感覺通過選項(xiàng)菜單來導(dǎo)入文件比寫代碼要方便多了……)
3.8.6 從其它程序加載文件
- 有些時(shí)候,我們會(huì)拿到某個(gè)類型的數(shù)據(jù)北启,但卻沒有對(duì)應(yīng)的原始程序卜朗,此時(shí)可以嘗試使用以下R包中的函數(shù)來讀取數(shù)據(jù)
文件格式 | 函數(shù) | R包 |
---|---|---|
ERSI ArcGIS | read.shapefile | shapefiles |
MATLAB | readMat | R.matlab |
minitab | read.mtp | foreign |
SAS(永久性數(shù)據(jù)集) | read.ssd | foreign |
SAS(XPORT格式) | read.xport | foreign |
SPSS | read.spss | foreign |
Stata | read.dta | foreign |
Systat | read.systat | foreign |
3.8.7 從數(shù)據(jù)庫中讀取數(shù)據(jù)
- DBI包可以通過驅(qū)動(dòng)程序連接至數(shù)據(jù)庫,要從某個(gè)數(shù)據(jù)庫中讀取數(shù)據(jù)咕村,首先需要下載其與DBI包相關(guān)聯(lián)的R包场钉,這些包為特定的數(shù)據(jù)庫程序的原始驅(qū)動(dòng)程序提供了API。例如懈涛,對(duì)于MySQL數(shù)據(jù)庫需要使用RMySQL包逛万,對(duì)于SQLite數(shù)據(jù)庫需要使用RSQLite包,等等
第四章 R的記號(hào)體系
- R的記號(hào)體系可以幫助我們從R對(duì)象中提取值批钠,一般的形式是先寫出對(duì)象名宇植,然后是一個(gè)中括號(hào),例如
x[ , ]
埋心,在R中有六種索引方式当纱,分別為正整數(shù)、負(fù)整數(shù)踩窖、零、空格晨横、邏輯值洋腮、名稱
4.1 正整數(shù)
- 如下,
students[1,1]
返回的值是第一行第一列的元素
> students <- data.frame(name=c('harry','ron','hermione'), gender=c('male','male','female'),age=c(17,17,17))
> students
name gender age
1 harry male 17
2 ron male 17
3 hermione female 17
> students[1,1]
[1] harry
- 如果想取多個(gè)數(shù)值手形,可以用向量代替數(shù)值作為索引的參數(shù)啥供,例如
students[c(1,2),1]
或students[1:2,1]
返回的是第一、第二行库糠,第一列的兩個(gè)元素
> students[1:2,1]
[1] harry ron
- 如果想提取一整行或一整列:
> students[1,] # 提取第一行
name gender age
1 harry male 17
> students[,1] # 提取第一列
[1] harry ron hermione
- 注意:如果從數(shù)據(jù)框中提取兩行或兩列以上的數(shù)據(jù)伙狐,將返回一個(gè)新的數(shù)據(jù)框,如果只提取一列瞬欧,則只會(huì)返回一個(gè)向量
4.2 負(fù)整數(shù)
- 和正整數(shù)索引相反贷屎,負(fù)整數(shù)索引將返回負(fù)整數(shù)索引對(duì)應(yīng)的元素之外的部分,例如艘虎,
students[-1,1]
將返回students
中第一行之外的所有元素唉侄,即第二、第三行
> students[-1,]
name gender age
2 ron male 17
3 hermione female 17
4.3 零索引
- 如果索引時(shí)使用0野建,那么返回的是一個(gè)空對(duì)象(沒啥用處……)
> students[0,0]
data frame with 0 columns and 0 rows
4.4 空格索引
- 其實(shí)就是上文所說的提取一整行或一整列的方法属划,
students[1,]
和students[1, ]
的效果是一樣的
4.5 邏輯值索引
- 這種方法將提取
TRUE
對(duì)應(yīng)的元素恬叹,FALSE
對(duì)應(yīng)的元素則不會(huì)提取,例如:
> students[c(TRUE, FALSE,TRUE),2]
[1] male female
4.6 名稱索引
- 這是從數(shù)據(jù)框中提取列的常用方法
> students[1:3, 'name']
[1] harry ron hermione
4.7 美元符號(hào)和雙中括號(hào)
- 美元符號(hào)可以很方便地提取出數(shù)據(jù)框中的某一列
> students$name
[1] harry ron hermione
- 如果一個(gè)列表中有若干個(gè)子列表同眯,雙中括號(hào)可以直接提取子列表中的元素绽昼,而不會(huì)返回一個(gè)列表對(duì)象
> l <- list(c(1,2,3), c(TRUE, FALSE))
> l
[[1]]
[1] 1 2 3
[[2]]
[1] TRUE FALSE
> l[1]
[[1]]
[1] 1 2 3
> l[[1]]
[1] 1 2 3
第五章 對(duì)象改值
5.1 就地改值
- 通過索引選擇想要更改的元素,然后將新的值通過
<-
賦給該對(duì)象须蜗,例如:
> x <- c(1,2,3,4,5)
> x[1] <- 100
> x
[1] 100 2 3 4 5
- 也可以批量改值硅确,例如:
> x[1:3] <- c(100,200,300)
> x
[1] 100 200 300 4 5
- 亦可以添加新的元素,例如:
> x[6] <- 6
> x
[1] 100 200 300 4 5 6
- 這種添加新元素的方法還可以用于在數(shù)據(jù)框中添加新變量(即唠粥,新的一列)
> students <- data.frame(name=c('harry','ron','hermione'), gender=c('male','male','female'),age=c(17,17,17))
> students$new <- 1:3
> students
name gender age new
1 harry male 17 1
2 ron male 17 2
3 hermione female 17 3
- 如果想刪除某一列疏魏,則賦值為
NULL
即可
> students$new <- NULL
> students
name gender age
1 harry male 17
2 ron male 17
3 hermione female 17
- 這些操作都是即時(shí)進(jìn)行的,所以在對(duì)數(shù)據(jù)框進(jìn)行修改之前晤愧,最好先保留一份備份
5.2 邏輯取子集
5.2.1 邏輯測試
- R中的七種邏輯運(yùn)算符
運(yùn)算符 | 語法 | 判別 |
---|---|---|
> | a>b | a是否大于b大莫? |
>= | a>=b | a是否大于或等于b? |
< | a<b | a是否小于b官份? |
<= | a<=b | a是否小于或等于b只厘? |
== | a==b | a是否等于b? |
!= | a!=b | a是否不等于b舅巷? |
%in% | a %in% c(a,b,c) | c(a,b,c) 中是否包含a羔味? |
- 對(duì)于每一個(gè)邏輯運(yùn)算符,R會(huì)將運(yùn)算符兩邊的值或向量進(jìn)行對(duì)比钠右,并返回邏輯值赋元,例如:
> 3 > c(1,2,3,4,5)
[1] TRUE TRUE FALSE FALSE FALSE
【tips】:
%in%
是唯一不進(jìn)行一一對(duì)比的運(yùn)算符,其主要是判斷左邊的值是否出現(xiàn)在右邊的對(duì)象中通過邏輯運(yùn)算符飒房,我們可以很方便地從對(duì)象中提取出我們想要的元素
> a <- c('group1','group2','group1','group2')
> b <- c(0.586, 0.762, 0.462, 0.631)
> a=='group1'
[1] TRUE FALSE TRUE FALSE
> b[a=='group1']
[1] 0.586 0.462
- 而且還可以使用多個(gè)運(yùn)算符
> b[a=='group1' & b>0.5]
[1] 0.586
- 邏輯值取子集非常強(qiáng)大搁凸,可以幫助我們快速定位、提取和修改對(duì)象中的元素狠毯。在使用這種方法時(shí)护糖,我們并不需要知道元素的具體位置,只需要知道如何用邏輯測試來描述這些元素即可
5.2.2 布爾運(yùn)算符
- 以下幾個(gè)運(yùn)算符可以將多個(gè)邏輯測試的結(jié)果整合并輸出為一個(gè)邏輯值(TRUE or FALSE)
運(yùn)算符 | 語法 | 判別 |
---|---|---|
& | cond1 & cond2 | cond1和cond2是否同時(shí)為真嚼松? |
| | cond1 pipe cond2 | cond1和cond2是否至少有一個(gè)為真嫡良? |
xor | xor(cond1,cond2) | cond1和cond2中是否只有一個(gè)為真? |
! | !cond1 | cond1是否為假献酗? |
any | any(cond1,cond2,cond3, ...) | 所有條件是否至少有一個(gè)為真寝受? |
all | all(cond1,cond2,cond3, ...) | 所有條件是否同時(shí)為真? |
- 例如:
> any(1>2, 'yes'=='no',2*2==4)
[1] TRUE
5.2.3 缺失信息
- R中的特殊字符
NA
代表“not available”罕偎,可用于儲(chǔ)存缺失信息羡蛾。如果運(yùn)算時(shí)存在缺少信息,那么NA
將被原封不動(dòng)地保留,例如:
> 1+NA
[1] NA
- 某些情況下痴怨,
NA
的存在會(huì)使數(shù)據(jù)處理變得棘手忙干,例如當(dāng)我們想計(jì)算一個(gè)向量中所有元素的均值,但向量中存在NA
浪藻,將會(huì)導(dǎo)致:
> mean(c(1,2,3,NA))
[1] NA
- 此時(shí)可以添加一個(gè)可選參數(shù)
na.rm
(大部分R函數(shù)都會(huì)存在這個(gè)參數(shù))捐迫,意味著“NA remove”,例如:
> mean(c(1,2,3,NA),na.rm = TRUE)
[1] 2
- 另外爱葵,我們還可以通過
is.na
函數(shù)來判斷是否存在NA
:
> is.na(NA)
[1] TRUE
> is.na(c(1,2,3,NA))
[1] FALSE FALSE FALSE TRUE
> any(is.na(c(1,2,3,NA)))
[1] TRUE
第六章 R的環(huán)境系統(tǒng)
6.1 R的環(huán)境系統(tǒng)
- R的環(huán)境系統(tǒng)很像電腦中的系統(tǒng)目錄施戴,是以層級(jí)結(jié)構(gòu)存儲(chǔ)的,其中萌丈,全局環(huán)境(globe environment)扮演著關(guān)鍵的作用赞哗,命令行中運(yùn)行的所有命令都是在全局環(huán)境中進(jìn)行的,在命令行中創(chuàng)建的所有對(duì)象也被存儲(chǔ)在全局環(huán)境中(見下圖)
- 任何時(shí)候辆雾,R的活動(dòng)環(huán)境(active environment)都只有一個(gè)肪笋,其會(huì)將所有的新對(duì)象存儲(chǔ)在當(dāng)前的活動(dòng)環(huán)境中,一般來說度迂,全局環(huán)境就是活動(dòng)環(huán)境
- 某些情況下藤乙,例如在運(yùn)行函數(shù)時(shí),R的活動(dòng)環(huán)境就變成了運(yùn)行時(shí)環(huán)境(runtime environment)惭墓,R會(huì)在這個(gè)新的環(huán)境中運(yùn)行該函數(shù)坛梁,并帶著函數(shù)運(yùn)行的結(jié)果回到調(diào)用該函數(shù)時(shí)的環(huán)境(也就是說,在函數(shù)內(nèi)部修改外部環(huán)境的對(duì)象時(shí)腊凶,修改的只是該對(duì)象的副本)
- 當(dāng)調(diào)用某個(gè)對(duì)象時(shí)划咐,R首先會(huì)在當(dāng)前環(huán)境中尋找該對(duì)象,如果沒有找到钧萍,就會(huì)進(jìn)入該環(huán)境的父環(huán)境(parent environment)中尋找尖殃,例如:
deal <- function(){
print(x)
}
x <- 'hello'
deal()
- 上述例子中,對(duì)象x是在全局環(huán)境中定義的划煮,當(dāng)運(yùn)行deal函數(shù)的時(shí)候,R首先會(huì)在該函數(shù)的活動(dòng)環(huán)境(也就是運(yùn)行時(shí)環(huán)境)中尋找x缔俄,但該環(huán)境中并不存在x弛秋,因此R進(jìn)入到該運(yùn)行時(shí)環(huán)境的父環(huán)境(也就是全局環(huán)境)中尋找x,這就是為什么函數(shù)內(nèi)部可以調(diào)用函數(shù)外部的對(duì)象俐载,但卻無法在全局環(huán)境中調(diào)用函數(shù)內(nèi)部的對(duì)象
第三部分
第七章 程序
7.1 策略
-
當(dāng)我們需要將一個(gè)復(fù)雜的任務(wù)編寫為R程序時(shí)蟹略,可以通過如下三個(gè)策略來簡化這個(gè)任務(wù)
- 將復(fù)雜任務(wù)分解成一些簡單的子任務(wù)
- 使用實(shí)例
- 用通俗的語言描述解決方案,然后將其轉(zhuǎn)換為R代碼
-
通扯粲叮可以將R程序分解為如下兩種子任務(wù)
- 有序步驟(sequential step):例如河內(nèi)塔問題就可以拆解成若干個(gè)步驟:把最大的圓盤移動(dòng)到目標(biāo)柱子挖炬、把第二大的圓盤移動(dòng)到目標(biāo)柱子……把最小的圓盤移動(dòng)到目標(biāo)柱子
- 同類情況(parallel case):以書中的簡化版老虎機(jī)為例,當(dāng)老虎機(jī)轉(zhuǎn)出三個(gè)同樣的符號(hào)時(shí)状婶,使用一種算法來計(jì)算獎(jiǎng)金意敛,當(dāng)轉(zhuǎn)出的符號(hào)都是杠馅巷,則使用第二種算法,其余情況則使用第三種草姻,等等
7.2 if和else語句
- 可以用if語句來統(tǒng)一處理某一類的情況钓猬,格式如下:
if (this) {
plan A
} else if (that) {
plan B
} else {
plan C
}
- this是某個(gè)邏輯測試或返回TRUE/FALSE的表達(dá)式,this為TRUE時(shí)運(yùn)行plan A撩独,如果this為FALSE而that為TRUE時(shí)敞曹,運(yùn)行plan B,如果this和that都為FALSE综膀,則屬于else的情況澳迫,此時(shí)運(yùn)行plan C
第八章 S3
- 先來看看下面這個(gè)例子,對(duì)象n的取值為1000000000剧劝,當(dāng)n的class(也就是“類”)是“numeric”時(shí)橄登,print出來的結(jié)果是1e+09,但當(dāng)n的class被替換為"POSIXct"和"POSIXt"后担平,print出來的結(jié)果就變成了一個(gè)時(shí)間
> n <- 1000000000
> class(n)
[1] "numeric"
> n
[1] 1e+09
> class(n) <- c("POSIXct", "POSIXt")
> class(n)
[1] "POSIXct" "POSIXt"
> n
[1] "2001-09-09 09:46:40 CST"
- 在上述例子中示绊,n的取值沒有變,但是class變了暂论,class的變化之所以會(huì)導(dǎo)致不同的輸出結(jié)果面褐,是因?yàn)镽對(duì)于不同的class有著不同的處理方式
- class是屬性的一種,屬性(attribute)取胎、泛型函數(shù)(generic function)和方法(method)展哭,三者共同構(gòu)成了R的S3系統(tǒng),這個(gè)系統(tǒng)掌管著R如何處理具有不同類的對(duì)象
8.1 屬性
- 可以使用attributes函數(shù)來查看一個(gè)對(duì)象的屬性闻蛀,例如匪傍,
gender
這個(gè)對(duì)象就有兩個(gè)屬性,一個(gè)是levels屬性觉痛,一個(gè)是class屬性
> gender <- factor(c('male','female','female'))
> attributes(gender)
$levels
[1] "female" "male"
$class
[1] "factor"
- 又例如役衡,剛剛提到的n,修改class之后薪棒,其屬性如下:
> attributes(n)
$class
[1] "POSIXct" "POSIXt"
- 我們還可以通過attr函數(shù)來給對(duì)象添加新的屬性手蝎,例如,我們給剛剛定義的n添加一個(gè)叫Hello的屬性俐芯,該屬性的值為World
> attr(n, 'Hello') <- "World"
- 現(xiàn)在用attributes函數(shù)來看看n的屬性棵介,可以發(fā)現(xiàn)新增了我們剛剛添加的屬性
> attributes(n)
$class
[1] "POSIXct"
$Hello
[1] "World"
8.2 泛型函數(shù)
- 在控制臺(tái)中輸入對(duì)象名n,R對(duì)此的反應(yīng)是
print(n)
吧史,但正如上一節(jié)提到的邮辽,n的取值保持不變,當(dāng)n的class改變的時(shí)候,print出來的內(nèi)容是不同的吨述,之所以print函數(shù)能根據(jù)不同情況/場合完成不同的任務(wù)(例如根據(jù)不同的class給出不同的結(jié)果)岩睁,是因?yàn)閜rint不是一個(gè)普通的函數(shù),而是一個(gè)泛型函數(shù)
8.3 方法
- 作為一個(gè)泛型函數(shù)锐极,
print()
的原理大致是這樣的笙僚,其首先會(huì)查找一個(gè)對(duì)象的class屬性,然后根據(jù)不同的class分配合理的輸出顯示方式 - 具體而言灵再,當(dāng)調(diào)用
print()
時(shí)肋层,其會(huì)調(diào)用一個(gè)名為UseMethod的函數(shù)(見第十章的代碼調(diào)試部分的圖示),該函數(shù)會(huì)檢查我們提供給print函數(shù)的第一個(gè)參數(shù)的class屬性翎迁,然后將我們提供的待輸出的對(duì)象交給一個(gè)新函數(shù)來處理栋猖。例如,對(duì)于一個(gè)class為POSIXct的對(duì)象汪榔,UseMethod會(huì)交給print.POSIXct函數(shù)來處理蒲拉,而對(duì)于一個(gè)class為factor的對(duì)象,會(huì)交給print.factor來處理 - 在這里痴腌,print.POSIXct和print.factor被稱為print函數(shù)的方法(method)雌团,這兩個(gè)函數(shù)本身是普通的R函數(shù),但特別之處在于R會(huì)調(diào)用它們?nèi)ヌ幚砭哂袑?duì)應(yīng)class屬性的對(duì)象
- 可以通過methods函數(shù)來查看一個(gè)泛型函數(shù)所支持的方法士聪,例如print函數(shù)支持將近200種方法
> methods(print)
[1] print.acf*
[2] print.anova*
[3] print.aov*
...
[183] print.xgettext*
[184] print.xngettext*
[185] print.xtabs*
8.4 小結(jié)
- 之所以稱為S3系統(tǒng)锦援,是由于其起源于S語言的第三個(gè)版本(S語言是R語言的前身),許多常見的R函數(shù)都是S3泛型函數(shù)剥悟,可以支持多種不同的類方法函數(shù)灵寺,S3系統(tǒng)使得R函數(shù)能在不同的場合有不同的表現(xiàn)
- R還有另外兩個(gè)創(chuàng)建class屬性行為的系統(tǒng)——S4系統(tǒng)和R5系統(tǒng),雖然使用難度較大区岗,但也提供了S3系統(tǒng)所沒有的防護(hù)措施
- 關(guān)于S3的編程方法略板,可以參考Handley Wickham所著的《advanced R programming》
第九章 循環(huán)
- 循環(huán)(loop)是R用來重復(fù)完成某個(gè)任務(wù)的方法
9.1 for循環(huán)
- 格式如下,that是一個(gè)對(duì)象集合慈缔,對(duì)于出現(xiàn)在that中的每一個(gè)值叮称,R都會(huì)循環(huán)運(yùn)行一遍兩個(gè)大括號(hào)之間的代碼(也就是this)
for (value in that) {
this
}
9.2 while循環(huán)
- 格式如下,當(dāng)condition為True時(shí)藐鹤,R會(huì)反復(fù)循環(huán)兩個(gè)大括號(hào)之間的代碼瓤檐,直到condition為False或用戶手動(dòng)停止程序(按下Esc鍵或RStudio控制臺(tái)面板上的停止圖標(biāo))
while (condition) {
code
}
9.3 repeat循環(huán)
- 格式如下,R會(huì)反復(fù)循環(huán)repeat中的代碼教藻,直到遇到了break命令
repeat{
code
if (this) {
break
}
}
9.4 小結(jié)
- 循環(huán)并非是在R中實(shí)現(xiàn)重復(fù)性任務(wù)自動(dòng)化的唯一途徑(例如,replicate函數(shù)也可以實(shí)現(xiàn))右锨,遺憾的是括堤,相比其它編程語言,循環(huán)代碼在R中的運(yùn)行速度更慢,但是別擔(dān)心悄窃,我們可以使用向量化編程來提高代碼的運(yùn)行速度讥电!
第十章 代碼提速
10.1 向量化代碼
- 向量化的代碼可以接受一個(gè)含有多個(gè)值的向量作為輸入,并且同時(shí)操作向量中的每個(gè)元素轧抗。其使用了R的三大法寶:邏輯測試恩敌,取子集和元素方式執(zhí)行
- 先來看一個(gè)例子,state.division這個(gè)數(shù)據(jù)集(來源于R中自帶的datasets包)記載的是美國各州所在的地區(qū)横媚,分別為New England, Middle Atlantic, South Atlantic, East South Central, West South Central, East North Central, West North Central, Mountain, and Pacific纠炮。這50個(gè)元素與state.name中的州名相互對(duì)應(yīng)
> state.division
[1] East South Central Pacific Mountain
[4] West South Central Pacific Mountain
[7] New England South Atlantic South Atlantic
[10] South Atlantic Pacific Mountain
[13] East North Central East North Central West North Central
[16] West North Central East South Central West South Central
[19] New England South Atlantic New England
[22] East North Central West North Central East South Central
[25] West North Central Mountain West North Central
[28] Mountain New England Middle Atlantic
[31] Mountain Middle Atlantic South Atlantic
[34] West North Central East North Central West South Central
[37] Pacific Middle Atlantic New England
[40] South Atlantic West North Central East South Central
[43] West South Central Mountain New England
[46] South Atlantic Pacific South Atlantic
[49] East North Central Mountain
9 Levels: New England Middle Atlantic ... Pacific
- 假如我們想計(jì)算“New England”這個(gè)地區(qū)的州的數(shù)量,那么非向量的方法會(huì)是這樣的(其中一種思路):
# 非向量化的代碼
count_loop <- function(){
count <- 0
for (i in 1:length(state.division)) {
if (state.division[i] == "New England") {
count <- count + 1
}
}
return(count)
}
- 在這個(gè)名為count_loop的函數(shù)中灯蝴,我們定義了一個(gè)名為
count
的對(duì)象來記錄州的數(shù)量恢口,然后通過for循環(huán)來遍歷state.division數(shù)據(jù)集中的每個(gè)元素,并通過條件語句來判斷某個(gè)元素是否為New England
穷躁,如果條件為TRUE
耕肩,則count
加1 - 運(yùn)行結(jié)果如下,“New England”有6個(gè)州
> count_loop()
[1] 6
- 向量化的代碼則可以是這樣的(只需要一行代碼即可完成任務(wù)):
# 向量化的代碼
count_set <- function(){
count <- length(state.division[state.division == "New England"])
return(count)
}
- 在這段代碼中问潭,我們先做了一個(gè)邏輯測試猿诸,即判斷state.division數(shù)據(jù)集中有哪些元素的值為“New England”
> state.division == "New England"
[1] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[11] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[21] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[31] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[41] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
- 然后我們基于返回的邏輯值,對(duì)state.division取子集(subsetting)
> state.division[state.division == "New England"]
[1] New England New England New England New England New England
[6] New England
于是狡忙,該子集的長度就是“New England”地區(qū)的州的數(shù)量啦梳虽,整個(gè)過程都是以元素方式執(zhí)行的
邏輯測試,取子集和元素方式執(zhí)行去枷,就是R語言的三大法寶怖辆,用這個(gè)方法編寫向量化的代碼,可以讓代碼飛速運(yùn)行
【tips】這段代碼甚至還可以變得更簡潔删顶,如下
# 向量化的代碼
count_set <- function(){
count <- sum(state.division == "New England")
return(count)
}
- 當(dāng)然竖螃,這里的例子比較簡單,所以兩種風(fēng)格的代碼的運(yùn)行效果相差無幾逗余,但對(duì)于大容量的數(shù)據(jù)特咆,向量化代碼的優(yōu)勢就很明顯了。書中給出了一個(gè)求1000萬個(gè)數(shù)值的絕對(duì)值的例子录粱,結(jié)果是向量化代碼的運(yùn)行速度比非向量化的代碼快30倍(我自己嘗試的結(jié)果是快3倍腻格,或許是和電腦性能有關(guān)系)
10.2 如何編寫向量化的代碼
- 有兩種方法:
- 對(duì)于程序中的有序步驟,使用向量化的函數(shù)來完成
- 對(duì)于同類情況啥繁,使用邏輯值取子集的方式來處理菜职,以便一次性處理完一類情況中的所有元素(for循環(huán)搭配if條件語句的組合常常能被邏輯值取子集所取代)
10.3 如何在R中編寫快速的for循環(huán)
向量化代碼并不意味著for循環(huán)就不應(yīng)該在R中使用了,當(dāng)使用for循環(huán)時(shí)旗闽,我們應(yīng)該注意改善循環(huán)的效率:1)能放在循環(huán)外的代碼就不要放在循環(huán)內(nèi)酬核,2)確保存儲(chǔ)循環(huán)輸出結(jié)果的對(duì)象有足夠的容量
對(duì)于第二點(diǎn)蜜另,書中提到一個(gè)例子,將100萬個(gè)數(shù)值循環(huán)放入一個(gè)名為output的對(duì)象嫡意,第一種方法是先定義一個(gè)長度為100萬的output举瑰,然后循環(huán)放入數(shù)值,第二種方法是先定義一個(gè)長度為1的output蔬螟,循環(huán)放入數(shù)值此迅,每次循環(huán)都增加output的長度。結(jié)果是旧巾,第一種方法的運(yùn)行時(shí)間不到兩秒鐘耸序,第二種方法的運(yùn)行時(shí)間則長達(dá)37分鐘。這是因?yàn)椴こ荩瑢?duì)于第一種方法佑吝,使用的都是同一個(gè)output,而第二種方法則需要不斷地復(fù)制绳匀、刪除舊的output芋忿,并在內(nèi)存中尋找新的地方存放output的新版本,相當(dāng)于讓R對(duì)output反復(fù)讀寫了100萬次
【tips】可以運(yùn)用
sys.time()
命令來測試某個(gè)函數(shù)的運(yùn)行時(shí)間
10.4 調(diào)試R代碼
- 這個(gè)是附錄里的內(nèi)容疾棵,方便起見就放在第十章的最后了(附錄中其他的內(nèi)容也已經(jīng)放在了各章節(jié)中合適的位置)
10.4.1 traceback
- 有時(shí)候我們需要在代碼中調(diào)用函數(shù)戈钢,調(diào)用的函數(shù)往往又會(huì)調(diào)用別的函數(shù),當(dāng)出現(xiàn)錯(cuò)誤時(shí)是尔,可能會(huì)難以定位究竟是哪個(gè)函數(shù)出了問題
- 這時(shí)候就可以在命令行中輸入
traceback()
殉了,該命令會(huì)顯示一個(gè)調(diào)用棧(call stack),即一個(gè)被調(diào)用函數(shù)的有序列表拟枚,其中第一行是出錯(cuò)的函數(shù)薪铜,最底層則是我們最初調(diào)用的函數(shù) - 不過要注意,出錯(cuò)的原因不一定發(fā)生在第一行的函數(shù)中恩溅,但一般來說隔箍,越上層的函數(shù),嫌疑越大
10.4.2 browser
在某個(gè)函數(shù)內(nèi)添加一行代碼
browser()
后脚乡,只要調(diào)用了該函數(shù)蜒滩,函數(shù)運(yùn)行到browser()
所在的一行時(shí)就會(huì)暫停,此時(shí)R處于一個(gè)新的模式奶稠,即瀏覽器模式(browser mode)(見debug部分的圖)-
瀏覽器模式有以下幾個(gè)特性:
- RStudio會(huì)顯示該函數(shù)的源代碼俯艰,并突出顯示該函數(shù)暫停時(shí)所在的代碼行
- 此時(shí)的運(yùn)行環(huán)境不再是全局環(huán)境,而是該函數(shù)的運(yùn)行時(shí)環(huán)境锌订,RStudio的環(huán)境面板也將顯示運(yùn)行時(shí)環(huán)境的所有對(duì)象
- 命令行窗口中的命令提示符
>
會(huì)被Browse[1]>
所取代竹握,我們可以在這里輸入一些命令,來檢查究竟是哪個(gè)地方出了錯(cuò)誤 - RStudio控制臺(tái)上方將出現(xiàn)“Next”辆飘、“Continue”和“Stop”三個(gè)按鈕啦辐,作用分別是:運(yùn)行該函數(shù)的下一行代碼污秆、運(yùn)行該函數(shù)剩余的所有代碼后退出瀏覽器模式、立刻中斷并退出瀏覽器模式昧甘。此外還可以在命令行輸入命令n、c战得、s來實(shí)現(xiàn)對(duì)應(yīng)按鈕的功能(如果函數(shù)中存在名稱為n充边、c、s常侦、Q的對(duì)象浇冰,那么輸入這些字母將無法查看對(duì)象,想要查看的話可以用
get('n')
這樣的方法)
10.4.3 斷點(diǎn)
- 打開腳本窗口聋亡,在函數(shù)中想要暫停的一行的左邊單擊鼠標(biāo)左鍵肘习,將顯示一個(gè)空心紅點(diǎn),即斷點(diǎn)(break point)坡倔,R會(huì)將斷點(diǎn)識(shí)別為添加
browser()
語句的信號(hào)漂佩,當(dāng)調(diào)用該函數(shù)時(shí),運(yùn)行到斷點(diǎn)所在的地方就會(huì)暫停并進(jìn)入瀏覽器模式(此時(shí)斷點(diǎn)會(huì)變?yōu)閷?shí)心紅點(diǎn))
10.4.4 debug
對(duì)于一個(gè)已經(jīng)存在的函數(shù)罪塔,可以使用debug函數(shù)來進(jìn)行調(diào)試(見下圖)投蝉,其作用相當(dāng)于在函數(shù)第一行添加一句
browser()
,調(diào)試完后可以使用undebug()
來將第一行的browser()
移除征堪,此外可以使用isdebugged()
來查看一個(gè)函數(shù)是否處于調(diào)試(debugging)模式如果嫌太麻煩瘩缆,可以用
debugonce()
代替debug()
,效果是下次運(yùn)行待調(diào)試函數(shù)時(shí)自動(dòng)進(jìn)入瀏覽器模式佃蚜,并在調(diào)試結(jié)束后解除該函數(shù)的調(diào)試模式
10.4.5 trace
- 可以使用trace函數(shù)來將
browser()
語句添加至函數(shù)中的任意位置庸娱,例如以下代碼可以將browser()
添加至名為“deal”的函數(shù)的第四行:
trace("deal",browser,at=4)
- 也可以用trace函數(shù)在函數(shù)中插入browser函數(shù)之外的函數(shù),但這么做的時(shí)候務(wù)必確保有充分的理由
- 調(diào)試結(jié)束后谐算,使用
untrace("deal")
來將函數(shù)恢復(fù)正常
10.4.6 recover
- 使用方法和
browser()
一樣熟尉,區(qū)別是可以輸入棧的編號(hào)來進(jìn)入調(diào)用棧的任意層級(jí),從而進(jìn)入某個(gè)函數(shù)的運(yùn)行時(shí)環(huán)境進(jìn)行調(diào)試 - 通過添加全局選項(xiàng)氯夷,可以使R在每次報(bào)錯(cuò)時(shí)自動(dòng)運(yùn)行
recover()
命令:
options(error=recover)
- 可以通過以下代碼來取消這一全局設(shè)置:
options(error=NULL)
?
----------2020.12.06更新----------
添加了第6臣樱、7、9腮考、10章的筆記
----------2020.12.07更新----------
添加了第8章的筆記
----------2020.12.14更新----------
添加了第2章和附錄部分的內(nèi)容雇毫,修正了諸多表述和錯(cuò)字
----------2020.12.2更新----------
添加了目錄