R語言系列1:數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)導入和常用函數(shù)
此文內(nèi)容為《R語言實戰(zhàn)》的筆記,人民郵電出版社出版。
從高中電腦課學VB開始,大一課內(nèi)開始學習C++,到后來大二為了數(shù)模學習Matlab,到大三為了搞深度學習自學Python,到研究生之初學習Stata——選擇一門語言對我來說就像是小時候玩冒險島,到10級的時候是轉(zhuǎn)戰(zhàn)士好還是弓箭手好一般的糾結(jié)。我查閱了很多B乎的文章,最后覺得可能R比較合適現(xiàn)在的我。
作為從Python轉(zhuǎn)進來R的新手,我把可能會用經(jīng)常需要用到或經(jīng)常需要查閱的代碼貼上來,主要是為了日后方便查找,就像“字典”一樣。推文的順序與教材不同,為了簡潔,我還會刪除一些我個人認為不太重要的章節(jié)。我還會按照自己的學習進度發(fā)布文章,請讀者見諒。
本文章僅供學習參考,請勿轉(zhuǎn)載,侵刪!
目錄
-
第2章 創(chuàng)建數(shù)據(jù)集
- 2.1 數(shù)據(jù)集的概念
- 2.2 數(shù)據(jù)結(jié)構(gòu)
- 2.2.1 向量
- 2.2.2 矩陣
- 2.2.3 數(shù)組
- 2.2.4 數(shù)據(jù)框
- A. attach(), detach(), with()
- B. 實例標識符
- 2.2.5 因子
- 2.2.6 列表
- 2.3 數(shù)據(jù)的輸入
- 2.3.1 從分隔符文件導入數(shù)據(jù)
- 2.3.2 導入Excel數(shù)據(jù)
- 2.3.3 導入Stata數(shù)據(jù)
- 2.5 處理對象的常用函數(shù)
第2章 創(chuàng)建數(shù)據(jù)集
按照個人要求的格式創(chuàng)建含有研究信息的數(shù)據(jù)集。在R中,這個任務包括兩步:
- 選擇一種數(shù)據(jù)結(jié)構(gòu)來儲存數(shù)據(jù)
- 將數(shù)據(jù)輸入或?qū)氲竭@個數(shù)據(jù)結(jié)構(gòu)中
2.1 數(shù)據(jù)集的概念
數(shù)據(jù)集是由數(shù)據(jù)構(gòu)成的一個矩形數(shù)組,行表示觀測,列表示變量。
2.2 數(shù)據(jù)結(jié)構(gòu)
R擁有的數(shù)據(jù)結(jié)構(gòu)有:
- 標量
- 向量
- 矩陣
- 數(shù)組
- 數(shù)據(jù)框
- 列表
在R中,對象(object)是指可以賦值給變量的任何事物;數(shù)據(jù)框(data frame)是R中用于儲存數(shù)據(jù)的一種結(jié)構(gòu):列表示標量,行表示觀測;因子(factor)是名義型標量或有序變量。
2.2.1 向量
向量是用于儲存數(shù)值型、字符型或邏輯型數(shù)據(jù)的一維數(shù)組。執(zhí)行組合功能的函數(shù)c()可以用來創(chuàng)建向量:
a <- c(1, 2, 5, 3, 6, -2, 4)
b <- c("one", "two", "three")
c <- c(TRUE, TRUE, TRUE, FALSE, TRUE, FALSE)
標量是只含一個元素的向量,例如
f <- 3
g <- "US"
h <- TRUE
通過在方括號中給定元素所處的位置的數(shù)值,可以訪問向量中的元素,例如:
a <- c("k", "j", "h", "a", "c", "m")
a[3]
## [1] "h"
最后一個語句中使用的冒號用于生成一個數(shù)值序列,例如a <- c(2:6)等價于a <- c(2, 3, 4, 5, 6)
2.2.2 矩陣
矩陣是一個二維數(shù)組,只是每個元素都有相同的模式(數(shù)值型、字符型或邏輯型)。可以通過matrix()創(chuàng)建矩陣,一般使用格式為:
mymatrix <- matrix(vector, nrow=number_of_rows, ncol=number_of_columns,
byrow=logical_value, dimnames=list(char_vector_rownames, char_vector_colnames))
其中,vector包含了矩陣的元素,nrow和ncol用以指定行和列的維數(shù),dimnames包含了可選的、以字符型向量表示的行名和列名。選項byrow則表明矩陣以行填充還是以列填充,默認情況下按行填充(TRUE)。
y <- matrix(1:20, nrow = 5)
y
## [,1] [,2] [,3] [,4]
## [1,] 1 6 11 16
## [2,] 2 7 12 17
## [3,] 3 8 13 18
## [4,] 4 9 14 19
## [5,] 5 10 15 20
cells <- c(1,26,24,28)
rnames <- c("R1", "R2")
cnames <- c("C1", "C2")
mymatrix <- matrix(cells, nrow = 2, dimnames = list(rnames, cnames))
mymatrix
## C1 C2
## R1 1 24
## R2 26 28
我們可以用下標和方括號來選擇矩陣中的行和列。X[i,]指定X中的第i行,X[,j]指定X中的第j列。X[i,j]指定第i行第j列個元素。選擇多個行和列時,下標i和j可以為數(shù)值型向量。
x <- matrix(1:10, nrow = 2, ncol = 5)
x
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
x[2,]
## [1] 2 4 6 8 10
x[,3]
## [1] 5 6
x[1, c(4,5)]
## [1] 7 9
矩陣都是二維的,和向量類似,矩陣也只能包含一種數(shù)據(jù)結(jié)構(gòu)。當維度超過2時,可以考慮使用數(shù)組;當數(shù)據(jù)類型超過1種時,可以考慮使用data frame。
2.2.3 數(shù)組
數(shù)組與矩陣類似,但維度可以大于2,可以通過array創(chuàng)建一個數(shù)組:
myarray <- array(vector, dimensions, dimnames)
其中,vector包含了數(shù)組中的數(shù)據(jù);dimensions是一個數(shù)值型向量,給出了維度下標的最大值;dimnames是可選的:
dim1 <- c("A1", "A2")
dim2 <- c("B1", "B2", "B3")
dim3 <- c("C1", "C2", "C3", "C4")
z <- array(1:24, c(2,3,4), dimnames = list(dim1, dim2, dim3))
z
## , , C1
##
## B1 B2 B3
## A1 1 3 5
## A2 2 4 6
##
## , , C2
##
## B1 B2 B3
## A1 7 9 11
## A2 8 10 12
##
## , , C3
##
## B1 B2 B3
## A1 13 15 17
## A2 14 16 18
##
## , , C4
##
## B1 B2 B3
## A1 19 21 23
## A2 20 22 24
可見,數(shù)組只是矩陣的自然推廣,而且數(shù)據(jù)結(jié)構(gòu)也只能有一種。
2.2.4 數(shù)據(jù)框
由于不同列可以包含不同模式的數(shù)據(jù),數(shù)據(jù)框的概念比矩陣更為一般。數(shù)據(jù)框是你會在R中最常見的數(shù)據(jù)結(jié)構(gòu)。、
數(shù)據(jù)框可以通過命令data.frame()創(chuàng)建:
mydata <- data.frame(col1, col2, col3,...)
其中的列向量col1、col2、col3可以為任何類型(字符、數(shù)值、邏輯)。每一列的列名可以用函數(shù)names指定:
patientID <- c(1, 2, 3, 4)
age <- c(24, 34, 28, 52)
diabetes <- c("Type1", "Type2", "Type1", "Type1")
status <- c("Poor", "Improve", "Excellent", "Poor")
patientdata <- data.frame(patientID, age, diabetes, status)
patientdata
## patientID age diabetes status
## 1 1 24 Type1 Poor
## 2 2 34 Type2 Improve
## 3 3 28 Type1 Excellent
## 4 4 52 Type1 Poor
其中,每一列的數(shù)據(jù)類型必須一樣,但不同列的可以不一樣。為了方便討論,數(shù)據(jù)框的列有時候被稱為變量。
選取數(shù)據(jù)框的元素有很多種。你可以使用前面提到的方括號的方法,也可以直接指定列名:
patientdata[1:2,]
## patientID age diabetes status
## 1 1 24 Type1 Poor
## 2 2 34 Type2 Improve
patientdata[,1:2]
## patientID age
## 1 1 24
## 2 2 34
## 3 3 28
## 4 4 52
patientdata[c("diabetes", "status")]
## diabetes status
## 1 Type1 Poor
## 2 Type2 Improve
## 3 Type1 Excellent
## 4 Type1 Poor
你也可以使用記號 $ 來選取一個給定數(shù)據(jù)框中的某個特定的變量:
patientdata$age
## [1] 24 34 28 52
如果想生成糖尿病類型diabetes和病情status的列聯(lián)表,可以使用下面的命令:
table(patientdata$diabetes, patientdata$status)
##
## Excellent Improve Poor
## Type1 1 0 2
## Type2 0 1 0
A. attach()、detach()和with()
每個變量名前面都鍵入一次patientdata非常麻煩,所以可以使用attach()、detach()、with()來簡化你的代碼。
1. attach 函數(shù)。 attach() 可以將數(shù)據(jù)框添加到R的搜索路徑中。R遇到一個變量名后,會檢查搜索路徑中的數(shù)據(jù)框,例如:
summary(patientdata$age)
plot(patientdata$patientID, patientdata$age)
就等同于
attach(patientdata)
summary(age)
plot(patientID, age)
detach(patientdata)
其中,detach()用于將搜索框從搜索路徑中移除。需要注意的是,detach()是可以省略的,但在寫程序的時候加上是良好的習慣。
重要的是,如果原始文件中已經(jīng)存在名為age或者patientID的變量,那么原變量會優(yōu)先于數(shù)據(jù)框中的列取得優(yōu)先權(quán)。
2. with 函數(shù)。另外一種方法是使用with()函數(shù)。可以這么寫:
with(patientdata, {
print(summary(age))
plot(patientID, age)
})
這種情況下,{}之間的語句都針對patientdata運行,就不許擔心變量名和列名沖突了。
with()的局限性在于,賦值僅在函數(shù)的括號內(nèi)生效。例如:
with(patientdata, {
stats <- summary(age)
stats
})
stats
是會報錯的,因為stats僅僅存在于with()環(huán)境中。這時候需要使用特殊賦值 <<- 代替標準的賦值符 <-,就可以把對象保存到 with() 外:
with(patientdata, {
stats <<- summary(age)
stats
})
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 24.0 27.0 31.0 34.5 38.5 52.0
stats
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 24.0 27.0 31.0 34.5 38.5 52.0
相對于attach(),更多的教材推薦使用with(),這只是個人習慣問題。
B. 實例標識符
在數(shù)據(jù)框中,病人編號(patientID)用于區(qū)分不同的個體。在R中,實例標識符(case identifier)可通過數(shù)據(jù)框操作函數(shù)中的rowname選項指定,例如:
patientdata <- data.frame(patientID, age, diabetes, status, row.names = patientID)
那么R就會將patientID作為R標記各類打印輸出所用的變量。
2.2.5 因子
變量了可以歸結(jié)為名義型、有序型或連續(xù)型。
名義型變量是沒有順序之分的類別變量,例如糖尿病類型
Diabetes(Type1, Type2),即使在數(shù)據(jù)中前者編碼為1、后者編碼為2,也不意味著二者是遞進關(guān)系。而病情
Status(poor, improved, excellent)則是順序型的。連續(xù)型變量可以呈現(xiàn)為一種某個范圍的任意值。
在R中,類別(名義型)變量和有序類別(有序型)變量均稱為因子(factor)。因子非常重要,它決定了數(shù)據(jù)的分析方式和視覺呈現(xiàn)效果。
函數(shù)factor()以一個整數(shù)向量的形式存儲類別值,整數(shù)的取值范圍為[1,...,k],同時一個由字符串組成的內(nèi)部向量將映射到這些整數(shù)上。例如:
diabetes <- c("Type1", "Type2", "Type1", "Type1")
diabetes <- facor(diabetes)
將此向量儲存為(1,2,1,1),并在內(nèi)部將其關(guān)聯(lián)為“Type1=1”、“Type2=2”。針對diabetes的任何分析都會將其作為名義型變量對待。
要表示有序變量,則需要使用factor()函數(shù)內(nèi)的ordered=TRUE,例如:
status <- c("Poor", "Improve", "Excellent", "Poor")
status <- c(status, ordered=TRUE)
會把status編碼為(3, 2, 1, 3)。對于字符型向量,因子水平默認按照字母順序創(chuàng)建,即“Poor=3”、“Improved=2”、“Excellent=1”。你也可以通過levels改變因子的順序:
status <- c("Poor", "Improve", "Excellent", "Poor")
status <- c(status, ordered=TRUE, levels=c("Poor", "Improved", "Excellent"))
那么就會將status編碼為:“Poor=1”、“Improved=2”、“Excellent=3”
數(shù)值型變量可以用levels和labels來編碼因子,例如男性編碼為1,女性編碼為2,那么:
sex <- facotr(sex, levels=c(1,2), labels=c("Male", "Female"))
把變量了轉(zhuǎn)換成一個無序因子。
總的來說:
patientID <- c(1, 2, 3, 4)
age <- c(24, 34, 28, 52)
diabetes <- c("Type1", "Type2", "Type1", "Type1")
status <- c("Poor", "Improve", "Excellent", "Poor")
diabetes <- factor(diabetes)
status <- factor(status, ordered = TRUE, levels = c("Poor", "Improved", "Excellent"))
patientdata <- data.frame(patientID, age, diabetes, status)
str(patientdata)
## 'data.frame': 4 obs. of 4 variables:
## $ patientID: num 1 2 3 4
## $ age : num 24 34 28 52
## $ diabetes : Factor w/ 2 levels "Type1","Type2": 1 2 1 1
## $ status : Ord.factor w/ 3 levels "Poor"<"Improved"<..: 1 NA 3 1
2.2.6 列表
列表(list)是R數(shù)據(jù)類型中最為復雜的一種。列表就是一些對象的有序結(jié)合,允許你整合若干對象到單個對象名下。可以使用list()創(chuàng)建列表:
mylist <- list(object1, object2, ...)
其對象可以是目前為止提到的任何結(jié)構(gòu)。還可以為列表中的對象命名:
mylist <- list(name1=object1, name2=object2, ...)
例如:
g <- "My First List"
h <- c(25:30)
j <- matrix(c(1:10), nrow = 2)
k <- c("one", "two", "three")
mylist <- list(title=g, h, matrix=j, English=k)
mylist
## $title
## [1] "My First List"
##
## [[2]]
## [1] 25 26 27 28 29 30
##
## $matrix
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
##
## $English
## [1] "one" "two" "three"
可以通過雙重括號指明某個成分的數(shù)字或名稱來訪問列表中的元素,例如mylist[[3]]和mylist[["matirx"]]均表示mylist的第三個元素。對于命名的成分,也可以用mylist$matrix來進行引用,例如:
mylist[[3]]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
mylist[["matrix"]]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
mylist$matrix
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
R中有很多函數(shù)的運行結(jié)果都是以列表的形式返回的,這是一個十分重要的數(shù)據(jù)結(jié)構(gòu)。
2.3 數(shù)據(jù)的輸入
2.3.1 從帶分隔符的文本文件中導入數(shù)據(jù)
可以使用read.table()從帶分隔符的文本中導入數(shù)據(jù)。此函數(shù)可以讀入一個表格格式的文件并將其保存為一個數(shù)據(jù)框,語法為:
mydataframe <- read.table(file, options)
其中,options是控制如何處理數(shù)據(jù)的選項,請查看help。
2.3.2 導入Excel數(shù)據(jù)
使用xlsx包可以讀取Excel數(shù)據(jù),首先在Console運行:
install.packages("xlsx")
然后運行:
library(xlsx)
read.xlsx(file, sheetIndex, header=TRUE)
其中,file是對應的xlsx文件路徑;sheetIndex指定第幾張工作表;header指定第一行是否為變量名。詳細見help。
2.3.3 導入Stata數(shù)據(jù)
可以使用readstata13包,然后運行:
library(readstata13)
read.dta13(file)
即可。具體的選項請看help。
2.5 處理對象的實用函數(shù)
處理對象的常用函數(shù)有:
length(object) # 顯示對象中元素/成分的數(shù)量
dim(object) # 顯示對象的維度
str(object) # 顯示某個對象的結(jié)構(gòu)
class(object) # 顯示對象的類或類型
mode(object) # 顯示對象的模式
names(object) # 顯示對象中各成分的名稱
c(object1,...) # 將對象合并為一個向量
cbind(object1,...) # 按列合并對象
rbind(object1,...) # 按行合并對象
object # 輸出某個對象
head(object) # 列出某個對象的開始部分
tail(object) # 列出某個對象的最后部分
ls() # 顯示當前對象列表