快速掌握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种类型是最常用的:向量、矩阵、数据框、时间序列。

可参考↓↓

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

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

  • 向量 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)亦可以实现数据连接功能。

参考→《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 缺失值处理

# 生成数据框  > 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()函数来生成索引,再匹配的数据的数值上面。

可参考↓↓

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

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

> 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. 去重与找重

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

可参考↓↓

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

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

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

> 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