快速掌握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