快速掌握R語言中類SQL數據庫操作技巧
- 2019 年 10 月 7 日
- 筆記
在數據分析中,往往會遇到各種複雜的數據處理操作:分組、排序、過濾、轉置、填充、移動、合併、分裂、去重、找重、填充等操作。這時候R語言就是一個很好的選擇:R可以高效地、優雅地解決數據處理操作。(本章節為R語言入門第二部分總結篇:數據操作)
本章內容布局思路:思來想後,想到SQL查詢的查詢思路可以作為本章節的布局思路
- 1.了解表結構/數據結構
- 2.對表中的一些數據做出修改、替換、甚至生成新字段
- 3.from:數據合併/連接
- 4.where:條件篩選/過濾
- 5.group:分組
6.having和select:呈現不明顯- 7.order:排序
- 8.其他補充
目錄
1. 初識R語言支持的數據類型
1.1 向量 Vector : c()
1.2 矩陣 Matrix: matrix()
1.3 數據框 DataFrame: data.frame()
1.4 時間序列 XTS: xts()
1.5 因子Factor:factor(補充)
2.查看數據概況
summary()和str()
3.修改/替換/重定義數據
4.數據合併
3.1 向量合併
3.2 cbind列合併(等長)
3.3 rbind行合併
3.4 merge
3.5 補充:集合操作
4.過濾/篩選
4.1 缺失值處理
4.2 數據增減
4.3 數值分段cut
5.分組操作
5.1 aggregate語法
5.2 aggregate分組計算
5.3 aggregate分組計算(formula形式)
6. 排序order
7. 計數table
8. 分裂split
9. 去重與找重unique
10.轉置
1. 初識R語言支持的數據類型
開始之前,需要先了解一下R語言支持的數據類型,以及這些常用類型的特點。以下4種類型是最常用的:向量、矩陣、數據框、時間序列。
可參考↓↓
- 向量 Vector : c()
- 矩陣 Matrix: matrix()
- 數據框 DataFrame: data.frame()
- 時間序列 XTS: xts()
- 因子Factor:factor(補充)

(圖片來自於粉絲日誌)
1.1 向量 Vector : c()
> x <- c(1:10) > x [1] 1 2 3 4 5 6 7 8 9 10
1.2 矩陣 Matrix: matrix()
#矩陣用法 matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE,dimnames = NULL) #表示生成1行,1列的一個矩陣,其中僅僅包含一個元素「NA」 #---示例---# > matrix(c(1,2,3, 11,12,13), nrow = 2, ncol = 3, byrow = TRUE, dimnames = list(c("row1", "row2"), c("C.1", "C.2", "C.3"))) C.1 C.2 C.3 row1 1 2 3 row2 11 12 13 #nrow = 2和ncol = 3 定義2x3的2行3列矩陣 #byrow = TRUE 是控制矩陣中的數據c(1,2,3, 11,12,13)按照行的順序排列,默認按照列排列 #dimnames = list(c("row1", "row2"), c("C.1", "C.2", "C.3")) 定義矩陣行名和列名
1.3 數據框 DataFrame: data.frame()
#其中" <- "是賦值的意思,將向量c(11:15)賦值給對象x > x <- c(11:15) > y <- c(1:5) #將向量x和y合併存儲到數據框中,並重命名為xf和yf > data.frame(xf = x, yf = y) xf yf 1 11 1 2 12 2 3 13 3 4 14 4 5 15 5
1.4 時間序列 XTS: xts()

> library(xts) > x <- c(11:15) > xts(x,order.by=as.Date('2019-09-14')+1:5) [,1] 2019-09-15 11 2019-09-16 12 2019-09-17 13 2019-09-18 14 2019-09-19 15
關於xts類型的詳細介紹,請參考文章《可擴展的時間序列xts》http://blog.fens.me/r-xts/
2.查看數據概況
> data(iris) > head(iris,10) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa 7 4.6 3.4 1.4 0.3 setosa 8 5.0 3.4 1.5 0.2 setosa 9 4.4 2.9 1.4 0.2 setosa 10 4.9 3.1 1.5 0.1 setosa > summary(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100 setosa :50 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300 versicolor:50 Median :5.800 Median :3.000 Median :4.350 Median :1.300 virginica :50 Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800 Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500 > str(iris) 'data.frame': 150 obs. of 5 variables: $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ... $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ... $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ... $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ... $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
3.修改/替換/重定義數據
修改指定單元格,修改指定列,within 關聯修改
leadership$age[leadership$age==99] <- NA leadership$agecat2 <- NA leadership <- within(leadership,{ agecat2[age>75] <- "Elder" agecat2[age>=55 & age<=75] <- "Middle Aged" agecat2[age<55] <- "Young"} )
4 數據合併
數據操作中,數據(集)合併是經常被用到。例如:合併來源不同,結構相似的兩個表格
3.1 向量合併
#一維向量合併直接將要合併的變量以","分割放到c()中即可。 > x <- c(11:20) > y <- c(1:10) > c(x,y) [1] 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5 6 7 8 9 10
3.2 cbind列合併(等長)
總結:cbind等行數、按列合併(無序)
#生成測試數據 > ID1 <- c(1:4) > ID2 <- c(2:5) > name<-c("A","B","C","D") > score<-c(8,22,7,6) > student1<-data.frame(ID1,name) > student2<-data.frame(ID2,score) #按照行合併student1和student2 > cbind(student1,student2) ID1 name ID2 score1 1 A 2 82 2 B 3 223 3 C 4 74 4 D 5 6
3.3 rbind行合併
總結:按行合併,需要注意數據集需要有相同的列字段名
> #生成測試數據student1 > ID <- c(1:4) > score <- c(8,22,7,33) > student1<-data.frame(ID,score)> #生成測試數據student2 > ID <- c("A","B","C","D") > score <- c(11,2,55,3) > student2<-data.frame(ID,score) #按行合併,需要注意數據集需要有相同的列字段名 > rbind(student1,student2) ID score1 1 82 2 223 3 74 4 335 A 116 B 27 C 558 D 3
3.4 merge
#merge語法結構 merge(x, y, by = intersect(names(x), names(y)), by.x = by, by.y = by, all = FALSE, all.x = all, all.y = all, sort = TRUE, suffixes = c(".x",".y"), no.dups = TRUE, incomparables = NULL, ...) #其中,通過by字段控制連接字段by = "ID"為單字段連接,by = c("ID","NAME",……)為多字段連接; #通過all=FALSE/TRUE、all.x = TRUE和all.y = TRUE實現內連接、外連接、左連接和右連接
#———merge用法———# > #生成測試數據 > ID1 <- c(1:4) > ID2 <- c(2:5) > name<-c("A","B","C","D") > score<-c(8,22,7,6) > student1<-data.frame(ID1,name) > student2<-data.frame(ID2,score) > > #內連接:保留交叉位置數據 > merge(student1,student2,by.x = "ID1", by.y = "ID2",all=TRUE) ID1 name score 1 1 A NA 2 2 B 8 3 3 C 22 4 4 D 7 5 5 <NA> 6 > #左連接:保留左邊所有數據及交叉y數據 > merge(student1,student2,by.x = "ID1", by.y = "ID2",all.x=TRUE) ID1 name score 1 1 A NA 2 2 B 8 3 3 C 22 4 4 D 7 > #右連接:保留右邊所有數據及交叉x數據 > merge(student1,student2,by.x = "ID1", by.y = "ID2",all.y=TRUE) ID1 name score 1 2 B 8 2 3 C 22 3 4 D 7 4 5 <NA> 6
3.5 補充:集合操作
集合操作,是對2個向量的操作,處理2個向量之間的數值的關係,找到包含關係、取交集、並集、差集等。、
# 定義2個向量x,y > x<-c(3:8,NA);x [1] 3 4 5 6 7 8 NA > y<-c(NA,6:10,NA);y [1] NA 6 7 8 9 10 NA # 判斷x與y重複的元素的位置 > is.element(x, y) [1] FALSE FALSE FALSE TRUE TRUE TRUE TRUE # 判斷y與x重複的元素的位置 > is.element(y, x) [1] TRUE TRUE TRUE TRUE FALSE FALSE TRUE # 取並集 > union(x, y) [1] 3 4 5 6 7 8 NA 9 10 # 取交集 > intersect(x, y) [1] 6 7 8 NA # 取x有,y沒有元素 > setdiff(x, y) [1] 3 4 5 # 取y有,x沒有元素 > setdiff(y, x) [1] 9 10 # 判斷2個向量是否相等 > setequal(x, y) [1] FALSE
數據連接主要涉及到merge函數和dplyr包中的*_join等函數,另外sqldf函數(SQL)亦可以實現數據連接功能。
4.過濾/篩選
過濾,是對數據集按照某種規則進行篩選,去掉不符合條件的數據,保留符合條件的數據。對於NA值的操作,主要都集中在了過濾操作和填充操作中,因此就不在單獨介紹NA值的處理了。
可參考↓↓
R語言 | 第一部分:數據預處理 7.數據篩選和8.抽樣
R語言數據管理與dplyr、tidyr | 第4講 5 dplyr中5.1篩選filter和5.3選擇select
4.1 缺失值處理
# 生成數據框 > df<-data.frame(a=c(1,NA,NA,2,NA), + b=c('B','A','B','B',NA), + c=c(rnorm(2),NA,NA,NA));df a b c 1 1 B -0.3041839 2 NA A 0.3700188 3 NA B NA 4 2 B NA 5 NA <NA> NA # 過濾有NA行的數據 > na.omit(df) a b c 1 1 B -0.3041839 # 過濾,保留b列值為B的數據 > df[which(df$b=='B'),] a b c 1 1 B -0.3041839 3 NA B NA 4 2 B NA
4.2 數據增減
常見如以下不同方法
#方法一:減行數或列數 x=x[,-1] #代表刪除x數據集中第一列數據 #方法二:dplyr::mutate#數值重定義和賦值 #將Ozone列取負數賦值給new,然後Temp列重新計算為(Temp - 32) / 1.8 mutate(airquality, new = -Ozone, Temp = (Temp - 32) / 1.8) #方法三:subset篩選變量服從某值的子集 subset(airquality, Temp > 80, select = c(Ozone, Temp))
4.3 數值分段
數值分段,就是把一個連續型的數值型數據,按區間分割為因子類型的離散型數據。
> x<-1:10;x [1] 1 2 3 4 5 6 7 8 9 10 # 把向量轉換為3段因子,分別列出每個值對應因子 > cut(x, 3) [1] (0.991,4] (0.991,4] (0.991,4] (0.991,4] (4,7] (4,7] (4,7] (7,10] (7,10] (7,10] Levels: (0.991,4] (4,7] (7,10] # 對因子保留2位精度,並支持排序 > cut(x, 3, dig.lab = 2, ordered = TRUE) [1] (0.99,4] (0.99,4] (0.99,4] (0.99,4] (4,7] (4,7] (4,7] (7,10] (7,10] (7,10] Levels: (0.99,4] < (4,7] < (7,10]
5 分組操作
此處僅講述aggregate數據分組計算內容,更多分組計算內容
參考→《R語言 分組計算,不止group_by》
- dplyr包中的group_by聯合summarize
- group_by和summarise單變量分組計算
- group_by和summarise多變量分組計算
- ddply分組計算示例
5.1 aggregate語法
aggregate(x, by, FUN) #x為數據集 #by為分組變量列表 #FUN為計算函數
5.2 aggregate分組計算
> row_names <- rep(c("A","B","C"),3) > col_names <- LETTERS[1:3] > df_matrix <- matrix(c(1:27),nrow = 9,dimnames = list(row_names,col_names)) > df_matrix A B C A 1 10 19 B 2 11 20 C 3 12 21 A 4 13 22 B 5 14 23 C 6 15 24 A 7 16 25 B 8 17 26 C 9 18 27 #注意分組變量為列表形式 > aggregate(df_matrix,list(Group = row_names), mean) Group A B C 1 A 4 13 22 2 B 5 14 23 3 C 6 15 24
5.3 aggregate分組計算補充(formula形式)
可以重點了解一下
aggregate(formula, data, FUN) #Formulas, one ~ one, one ~ many, many ~ one, and many ~ many: #一組對一計算變量函數型分組計算:計算變量~分組變量 > aggregate(weight ~ feed, data = chickwts, mean) feed weight 1 casein 323.5833 2 horsebean 160.2000 3 linseed 218.7500 4 meatmeal 276.9091 5 soybean 246.4286 6 sunflower 328.9167 #多組對一函數型分組計算:計算變量~分組變量1+分組變量2…… > aggregate(breaks ~ wool + tension, data = warpbreaks, mean) wool tension breaks 1 A L 44.55556 2 B L 28.22222 3 A M 24.00000 4 B M 28.77778 5 A H 24.55556 6 B H 18.77778 #一組對多計算變量,函數型分組計算:cbind(計算變量1,計算變量2)~分組變量1 > aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, mean) Month Ozone Temp 1 5 23.61538 66.73077 2 6 29.44444 78.22222 3 7 59.11538 83.88462 4 8 59.96154 83.96154 5 9 31.44828 76.89655 #多組對多計算變量,函數型分組計算:cbind(計算變量1,計算變量2)~分組變量1+分組變量2…… > aggregate(cbind(ncases, ncontrols) ~ alcgp + tobgp, data = esoph, sum) alcgp tobgp ncases ncontrols 1 0-39g/day 0-9g/day 9 261 2 40-79 0-9g/day 34 179 3 80-119 0-9g/day 19 61 4 120+ 0-9g/day 16 24 5 0-39g/day 10-19 10 84 6 40-79 10-19 17 85 7 80-119 10-19 19 49 8 120+ 10-19 12 18 9 0-39g/day 20-29 5 42 10 40-79 20-29 15 62 11 80-119 20-29 6 16 12 120+ 20-29 7 12 13 0-39g/day 30+ 5 28 14 40-79 30+ 9 29 15 80-119 30+ 7 12 16 120+ 30+ 10 13
6. 排序
#order默認升序,變量前加「-」代表降序
#排序的操作,大多都是基於索引來完成的
#用order()函數來生成索引,再匹配的數據的數值上面。
可參考↓↓
> row_names <- rep(c("A","B","C"),3) > col_names <- LETTERS[1:3] > set.seed(1234) > df_matrix <- matrix(round(rnorm(27,0,1),3),nrow = 9,dimnames = list(NULL,col_names));df_matrix A B C [1,] -1.207 -0.890 -0.837 [2,] 0.277 -0.477 2.416 [3,] 1.084 -0.998 0.134 [4,] -2.346 -0.776 -0.491 [5,] 0.429 0.064 -0.441 [6,] 0.506 0.959 0.460 [7,] -0.575 -0.110 -0.694 [8,] -0.547 -0.511 -1.448 [9,] -0.564 -0.911 0.575 > df_frame <- data.frame(group=row_names,df_matrix);df_frame group A B C 1 A -1.207 -0.890 -0.837 2 B 0.277 -0.477 2.416 3 C 1.084 -0.998 0.134 4 A -2.346 -0.776 -0.491 5 B 0.429 0.064 -0.441 6 C 0.506 0.959 0.460 7 A -0.575 -0.110 -0.694 8 B -0.547 -0.511 -1.448 9 C -0.564 -0.911 0.575 > > #order,其中默認升序,變量前加「-」代表降序 > #排序的操作,大多都是基於索引來完成的 > #用order()函數來生成索引,再匹配的數據的數值上面。 > df_frame[order(df_frame$A),] group A B C 4 A -2.346 -0.776 -0.491 1 A -1.207 -0.890 -0.837 7 A -0.575 -0.110 -0.694 9 C -0.564 -0.911 0.575 8 B -0.547 -0.511 -1.448 2 B 0.277 -0.477 2.416 5 B 0.429 0.064 -0.441 6 C 0.506 0.959 0.460 3 C 1.084 -0.998 0.134 > df_frame[order(df_frame$group,-df_frame$A),] group A B C 7 A -0.575 -0.110 -0.694 1 A -1.207 -0.890 -0.837 4 A -2.346 -0.776 -0.491 5 B 0.429 0.064 -0.441 2 B 0.277 -0.477 2.416 8 B -0.547 -0.511 -1.448 3 C 1.084 -0.998 0.134 6 C 0.506 0.959 0.460 9 C -0.564 -0.911 0.575
7. 計數
計數,是統計同一個值出現的次數。
# 生成20個隨機數的向量 set.seed(1234) x<-round(rnorm(20)*5);x # 統計每個值出現的次數 table(x) hist(x,xlim = c(-10,13),breaks=5)
8 數據分裂
分裂計算,是把一個向量按照一列規則,拆分成多個向量的操作。有時候分裂split也被用於分組計算中。
> row_names <- rep(c("A","B","C"),3) > col_names <- LETTERS[1:3] > df_matrix <- matrix(c(1:27),nrow = 9,dimnames = list(NULL,col_names)) > row_names <- rep(c("A","B","C"),3) > col_names <- LETTERS[1:3] > df_matrix <- matrix(c(1:27),nrow = 9,dimnames = list(NULL,col_names));df_matrix A B C [1,] 1 10 19 [2,] 2 11 20 [3,] 3 12 21 [4,] 4 13 22 [5,] 5 14 23 [6,] 6 15 24 [7,] 7 16 25 [8,] 8 17 26 [9,] 9 18 27 > df_frame <- data.frame(group=row_names,df_matrix);df_frame group A B C 1 A 1 10 19 2 B 2 11 20 3 C 3 12 21 4 A 4 13 22 5 B 5 14 23 6 C 6 15 24 7 A 7 16 25 8 B 8 17 26 9 C 9 18 27 > df_split <- split(df_frame,row_names);df_split $A group A B C 1 A 1 10 19 4 A 4 13 22 7 A 7 16 25 $B group A B C 2 B 2 11 20 5 B 5 14 23 8 B 8 17 26 $C group A B C 3 C 3 12 21 6 C 6 15 24 9 C 9 18 27
另外,可以用因子類型來控制分裂。分成2步操作,第一步先分成與數據集同樣長度的因子,第二步進行分裂,可以把一個大的向量拆分成多個小的向量。
> # 生成因子規則 > n <- 3; size <- 5 > fat <- factor(round(n * runif(n * size)));fat [1] 3 3 1 1 0 1 2 1 3 3 1 1 2 2 2 Levels: 0 1 2 3 > # 生成數據向量 > x <- rnorm(n * size);x [1] -1.2107366 -1.3102467 -0.4083354 -0.5629753 1.2139442 1.6288760 -0.3160227 -1.8076242 -0.6125961 [10] -2.1066644 1.2053009 1.3294407 -0.6836288 -1.7868047 0.1364916 > # 對向量以因子的規則進行拆分 > split(x, fat) $`0` [1] 1.213944 $`1` [1] -0.4083354 -0.5629753 1.6288760 -1.8076242 1.2053009 1.3294407 $`2` [1] -0.3160227 -0.6836288 -1.7868047 0.1364916 $`3` [1] -1.2107366 -1.3102467 -0.6125961 -2.1066644
9. 去重與找重
去重,是把向量中重複的元素過濾掉。找重,是把向量中重複的元素找出來。
可參考↓↓
> x<-c(3:6,5:8);x [1] 3 4 5 6 5 6 7 8 # 去掉重複元素 > unique(x) [1] 3 4 5 6 7 8 # 找到重複元素,索引位置 > duplicated(x) [1] FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE # 找到重複元素 > x[duplicated(x)] [1] 5 6
10.轉置
轉置是一個數學名詞,把行和列進行互換,一般用於對矩陣的操作。
# 創建一個3行5列的矩陣 > m<-matrix(1:15,ncol=5);m [,1] [,2] [,3] [,4] [,5] [1,] 1 4 7 10 13 [2,] 2 5 8 11 14 [3,] 3 6 9 12 15 # 轉置後,變成5行3列的矩陣 > t(m) [,1] [,2] [,3] [1,] 1 2 3 [2,] 4 5 6 [3,] 7 8 9 [4,] 10 11 12 [5,] 13 14 15