【R】《R語言入門與實(shí)踐》讀書筆記

最近在學(xué)習(xí)R凯砍,主要在看《R語言入門與實(shí)踐》這本書(Garrett Grolemund著,馮凌秉譯拴竹,人民郵電出版社)悟衩,做了一些筆記,分享給大家

目錄

這篇筆記的PDF版本:https://pan.baidu.com/s/1PB874TCKAWOP65TM6euFPg
提取碼:08kx

第一部分

第一章 R基礎(chǔ)

1.1 下載栓拜、安裝R和RStudio

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膜赃、m2s是函數(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)

第二章 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ì)算:

    1. 當(dāng)對(duì)象y的值為4時(shí)佳恬,x+y意味著x中每個(gè)元素加4
    2. 當(dāng)y也是向量時(shí),x+y意味著對(duì)應(yīng)索引的元素相加
  • 原子型向量的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ù)nrowncol來設(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
  • 當(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ù)

    1. 將復(fù)雜任務(wù)分解成一些簡單的子任務(wù)
    2. 使用實(shí)例
    3. 用通俗的語言描述解決方案,然后將其轉(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 如何編寫向量化的代碼

  • 有兩種方法:
    1. 對(duì)于程序中的有序步驟,使用向量化的函數(shù)來完成
    2. 對(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更新----------
添加了目錄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市踩蔚,隨后出現(xiàn)的幾起案子棚放,更是在濱河造成了極大的恐慌,老刑警劉巖馅闽,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件飘蚯,死亡現(xiàn)場離奇詭異馍迄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)局骤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門攀圈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人峦甩,你說我怎么就攤上這事赘来。” “怎么了凯傲?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵犬辰,是天一觀的道長。 經(jīng)常有香客問我冰单,道長幌缝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任诫欠,我火速辦了婚禮涵卵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好镐依,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贴硫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伊者。 梳的紋絲不亂的頭發(fā)上英遭,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音亦渗,去河邊找鬼挖诸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛法精,可吹牛的內(nèi)容都是我干的多律。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼搂蜓,長吁一口氣:“原來是場噩夢啊……” “哼狼荞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起帮碰,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤相味,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后殉挽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丰涉,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拓巧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了一死。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肛度。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖投慈,靈堂內(nèi)的尸體忽然破棺而出贤斜,到底是詐尸還是另有隱情,我是刑警寧澤逛裤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站猴抹,受9級(jí)特大地震影響带族,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蟀给,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一蝙砌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧跋理,春花似錦择克、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拭卿,卻和暖如春骡湖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背峻厚。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工响蕴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惠桃。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓浦夷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辜王。 傳聞我的和親對(duì)象是個(gè)殘疾皇子劈狐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容