快速掌握R语言中类SQL数据库操作技巧

2019-09-25 16:29:46 浏览数 (1)

在数据分析中,往往会遇到各种复杂的数据处理操作:分组、排序、过滤、转置、填充、移动、合并、分裂、去重、找重、填充等操作。这时候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种类型是最常用的:向量、矩阵、数据框、时间序列。

可参考↓↓

R语言|第2讲:生成数据

R语言快速入门:数据结构 生成数据 数据引用 读取外部数据

  • 向量 Vector : c()
  • 矩阵 Matrix: matrix()
  • 数据框 DataFrame: data.frame()
  • 时间序列 XTS: xts()
  • 因子Factor:factor(补充)

(图片来自于粉丝日志)

1.1 向量 Vector : c()

代码语言:javascript复制
> x <- c(1:10)
> x
 [1]  1  2  3  4  5  6  7  8  9 10

1.2 矩阵 Matrix: matrix()

代码语言:javascript复制
#矩阵用法
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()

代码语言:javascript复制
#其中" <- "是赋值的意思,将向量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()

代码语言:javascript复制
> 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/

代码语言:javascript复制
2.查看数据概况
代码语言:javascript复制
> 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 关联修改

代码语言:javascript复制
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 向量合并

代码语言:javascript复制
#一维向量合并直接将要合并的变量以","分割放到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等行数、按列合并(无序)

代码语言:javascript复制
#生成测试数据
> 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行合并

总结:按行合并,需要注意数据集需要有相同的列字段名

代码语言:javascript复制
> #生成测试数据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

代码语言:javascript复制
#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实现内连接、外连接、左连接和右连接
代码语言:javascript复制
#———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个向量之间的数值的关系,找到包含关系、取交集、并集、差集等。、

代码语言:javascript复制
# 定义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
代码语言:javascript复制
数据连接主要涉及到merge函数和dplyr包中的*_join等函数,另外sqldf函数(SQL)亦可以实现数据连接功能。

参考→《R语言 数据(集)合并与连接/匹配 | 专题2》

4.过滤/筛选

过滤,是对数据集按照某种规则进行筛选,去掉不符合条件的数据,保留符合条件的数据。对于NA值的操作,主要都集中在了过滤操作和填充操作中,因此就不在单独介绍NA值的处理了。

可参考↓↓

R语言 | 第一部分:数据预处理 7.数据筛选和8.抽样

R语言数据管理与dplyr、tidyr | 第4讲 5 dplyr中5.1筛选filter和5.3选择select

R 语言 逻辑运算:TRUE/FALSE | 专题3

4.1 缺失值处理

代码语言:javascript复制
# 生成数据框
> 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 数据增减

常见如以下不同方法

代码语言:javascript复制
#方法一:减行数或列数
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 数值分段

数值分段,就是把一个连续型的数值型数据,按区间分割为因子类型的离散型数据。

代码语言:javascript复制
> 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]
代码语言:javascript复制

5 分组操作

此处仅讲述aggregate数据分组计算内容,更多分组计算内容

参考→《R语言 分组计算,不止group_by》

  • dplyr包中的group_by联合summarize
  • group_by和summarise单变量分组计算
  • group_by和summarise多变量分组计算
  • ddply分组计算示例

5.1 aggregate语法

代码语言:javascript复制
aggregate(x, by, FUN)
#x为数据集
#by为分组变量列表
#FUN为计算函数

5.2 aggregate分组计算

代码语言:javascript复制
> 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形式)

可以重点了解一下

代码语言:javascript复制
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()函数来生成索引,再匹配的数据的数值上面。

可参考↓↓

R语言 排序&去重操作 | 专题1

R语言 | 第一部分:数据预处理

代码语言:javascript复制
> 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. 计数

计数,是统计同一个值出现的次数。

代码语言:javascript复制
# 生成20个随机数的向量
set.seed(1234)
x<-round(rnorm(20)*5);x
# 统计每个值出现的次数
table(x)
hist(x,xlim = c(-10,13),breaks=5)
代码语言:javascript复制

8 数据分裂

分裂计算,是把一个向量按照一列规则,拆分成多个向量的操作。有时候分裂split也被用于分组计算中。

代码语言:javascript复制
> 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步操作,第一步先分成与数据集同样长度的因子,第二步进行分裂,可以把一个大的向量拆分成多个小的向量。

代码语言:javascript复制
> # 生成因子规则
> 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. 去重与找重

去重,是把向量中重复的元素过滤掉。找重,是把向量中重复的元素找出来。

可参考↓↓

R语言 | 第一部分:数据预处理

R语言 排序&去重操作 | 专题1

R 语言 逻辑运算:TRUE/FALSE | 专题3

代码语言:javascript复制
> 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
代码语言:javascript复制
10.转置

转置是一个数学名词,把行和列进行互换,一般用于对矩阵的操作。

代码语言:javascript复制
# 创建一个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

0 人点赞