学习之旅14-R基本数据管理(二)

13 篇文章 0 订阅
7 篇文章 0 订阅

前言

  • 上一节 学习之旅13-R基本数据管理(一)中,我们梳理了关于变量,因子的内容,并就如何创建变量以及变量的重编码,重命名做了简单介绍,这一节我们将进一步对数据的管理做详细介绍,比如缺失值如何查询、剔除,如何对数据做进一步转化,数据集的合并,查询子集等等。

4、数据基本管理

4.2 缺失值

  • 缺失值在很对场景都会出现,即数据可能由于某种原因导致的不存在或者不完整,在R中缺失值的符号为NA(not variable,不可用),不管是字符型还是数值型,缺失值都表示为NA。

4.2.1 缺失值的判断

  • is.na()函数来进行缺失值的检测。该函数可以作用于任何一个对象上,返回一个相同大小的对象,若某个元素是缺失值,则对应位置返回TRUE。
> na01 <- c(1, 2, 3, NA)
> is.na(na01)
[1] FALSE FALSE FALSE  TRUE
> id <- c(1, 2, 3, 4)
> sex <- c("男", "男", NA, NA)
> age <- c(18, 21, 19, 20)
> data01 <- data_frame(id, sex, age)
> data01
# A tibble: 4 x 3
     id sex     age
  <dbl> <chr> <dbl>
1     118
2     221
3     3 NA       19
4     4 NA       20
> is.na(data01)
        id   sex   age
[1,] FALSE FALSE FALSE
[2,] FALSE FALSE FALSE
[3,] FALSE  TRUE FALSE
[4,] FALSE  TRUE FALSE

注意:
(1)缺失值是不可比较的,故无法用比较运算符来检测缺失值是否存在,即na01 == NA 的结果永远不会是TRUE。
(2)对于极限值(Inf正无穷,-Inf负无穷),R在处理这些值是并不会把他们标记为缺失值,因为这是值是存在的,只不过不是一个确实的数(not a number),对于这类数只能用is.infinite()和is.nan()来检测。
NaN:无定义数用NaN表示,即“Not a Number(非数)”。不过在R中,R实际上是把NaN视作一个数的,当其参与运算时,返回结果总是NaN。is.nan()函数来检测计算结果有无定义。
NULL:R语言中,NA代表位置上的值为空(即有一个位置,只是这个值因为某些原因缺失了),NULL代表连位置都没有,变量为空,其长度为0,表明“空无一物”
在这里插入图片描述

> na01 == NA #无法做比较,返回的永远不会是TRUE
[1] NA NA NA NA
> t1 <- 1/0 #t1 为一个正无穷大的数,此时只有用is.infinite()判断后返回的值才是TRUE,其他返回均为FALSE
> t1
[1] Inf
> is.na(t1)
[1] FALSE
> is.nan(t1)
> is.finite(t1) #有限大时返回TRUE
[1] FALSE
> t2 <- NULL
> t3 <- NA
> length(t2)
[1] 0
> length(t3)
[1] 1

4.2.1 重编码为缺失值

  • 对于数据中的某些值,我们希望在特定的情况下重新编码为缺失值,此时我们通过指定哪些值需要重编码即可。具体可以参考上一节4.1.2 变量重编码。
> data01
# A tibble: 4 x 3
     id sex     age
  <dbl> <chr> <dbl>
1     118
2     221
3     3 NA       19
4     4 NA       20
> data01$age[data01$age == 21] <- NA
> data01
# A tibble: 4 x 3
     id sex     age
  <dbl> <chr> <dbl>
1     118
2     2NA
3     3 NA       19
4     4 NA       20

4.2.1 排除缺失值

  • 对于某些缺失值,我们在进行计算时必须将其剔除,不然计算出来的结果也是缺失值。当然大多数函数拥有na.rm=TRUE选项,可以在进行计算之前将缺失值先排除,然后在计算剩余的值。
> x <- c(1, 3, 5, NA)
> sum(x)
[1] NA
> x <- c(1, 3, 5, NA)
> sum(x)
[1] NA
  • na.omit()可以移除所有缺失值的观测,对于数据框来说,使用这个行数则剔除含有缺失值的行(行删除)。当然这只是其中一种,对于复杂的缺失值处理,我们会在后面的内容中讲解其他方法。
> data01
# A tibble: 4 x 3
     id sex     age
  <dbl> <chr> <dbl>
1     118
2     2NA
3     3 NA       19
4     4 NA       20
> na.omit(data01)
# A tibble: 1 x 3
     id sex     age
  <dbl> <chr> <dbl>
1     118

4.3 日期值

  • R语言中我们通常以字符串的形录入,我们需要转化成数值形式存储日期变量时就需要as.Date(data, format = “format”),data表示需要转化成数值型的日期数据(字符型),format表示我们永远要转化成的日期格式,常见日期格式如下:只有转化成数值型后我们才能进行日期的计算。

在这里插入图片描述

  • 默认输出格式为yyyy-mm-dd
> data01
# A tibble: 4 x 3
     id sex     age
  <dbl> <chr> <dbl>
1     118
2     2NA
3     3 NA       19
4     4 NA       20
> birdate <- c("1993-09-02","1992-01-02","1992-03-02","1995-04-20") # 我们以字符串形式保存一个日期变量birdate
> str(birdate) # 可以看到此时类型为chr
 chr [1:4] "1993-09-02" "1992-01-02" "1992-03-02" "1995-04-20"
> day <- birdate[1]-birdate[2]  #此时计算birdate中第一个日期和第二个日期间的时间间隔就会报错。
Error in birdate[1] - birdate[2] : 二进列运算符中有非数值参数
> birdate <- as.Date(birdate)  # 通过函数转化为数值形式,不加参数默认yyyy-mm-dd
> str(birdate) #此时转化成数值形式的日期格式
 Date[1:4], format: "1993-09-02" "1992-01-02" "1992-03-02" "1995-04-20"
> day <- birdate[1]-birdate[2] #可以进行计算,相隔609天
> day
Time difference of 609 days
> > mydate <- c("03/02/1993", "03/05/1992","03/12/1991","28/09/1995")
> mydate
[1] "03/02/1993" "03/05/1992" "03/12/1991" "28/09/1995"
> str(mydate)
 chr [1:4] "03/02/1993" "03/05/1992" "03/12/1991" "28/09/1995"
 > mformat <- "%d/%m/%Y" # 指定需要读入的日期格式,务必与之一一对应
> mydate1 <- as.Date(mydate, mformat)
> mydate1
[1] "1993-02-03" "1992-05-03" "1991-12-03" "1995-09-28"

以下代码中我的mydate存储的为dd-mm-yyyy,因此我需要指定读入的格式也必须是dd-mm-yyyy,即"%d/%m/%Y",若我们使用"%m/%d/%Y",对于"28/09/1995",没有28这个月份,因此as.Date()转化出来的这个值就是NA。

> mydate <- c("03/02/1993", "03/05/1992","03/12/1991","28/09/1995")
> mydate
[1] "03/02/1993" "03/05/1992" "03/12/1991" "28/09/1995"
> str(mydate)
 chr [1:4] "03/02/1993" "03/05/1992" "03/12/1991" "28/09/1995"
> mformat <- "%m/%d/%Y"
> mydate1 <- as.Date(mydate, mformat)
> mydate1
[1] "1993-03-02" "1992-03-05" "1991-03-12" NA
  • Sys.Date()查看当天的日期,date()返回当前日期和具体时间。数字和字符串可以使用 format()函数指定参数按某种格式输出。
> Sys.Date()
[1] "2021-03-01"
> date()
[1] "Mon Mar 01 22:02:55 2021"
> today <- Sys.Date()
> today
[1] "2021-03-01"
> format(today, format="%Y %m %B")
[1] "2021 03 三月"
> format(today, format="%Y/%m/%B")
[1] "2021/03/三月"

R的内部在存储日期时,是使用自1970年1月1日以来的天数表示的,更早的日期则表示为负数。故可以进行计算时间间隔:difftime(time1, time2, tz,units = c(“auto”, “secs”, “mins”, “hours”,“days”, “weeks”))函数可以用于计算(time1-time2)。tz:用于转换的可选时区规范,主要用于“POSIXlt”对象。units :计算相关的秒数、分钟数、小时数、天数、周数。

> day1 <- as.Date("1993-08-08")
> day2 <- Sys.Date()
> day2
[1] "2021-03-01"
> > day2-day1
Time difference of 10067 days
> difftime(day2, day1,units = "days") #day2 - day1 
Time difference of 10067 days

4.3.1 日期值转化

  • 有时我们为了对日期做一些处理,此时转化成字符型变量后,我们能更好的进行数据处理(取子集,替换,连接等):通过函数as.character()转化为字符类型。

4.4 类型转化

  • 上面我们谈到了日期格式的相互转化,在R中我们经常需要在各种数值,字符之间进行转化,R提供了一系列类型判断和转化的函数:

在这里插入图片描述

> x <- c(1, 3, 5)
> y <- c(20, "张三", "李四")
> data01
  key Pa Pb
1   5 12 10
2  10 17 15
3  15 20 21
4  20 23 22
5  25 30 27
> # 我们定义了以上数据,x为一个向量,里面的元素都是数值型,y也是一个向量,但是里面数据都是字符型(虽然有20 ,但是也是字符),data01为一个数据框
> > is.numeric(x) #判断是否为数值,输出TURE和FALSE
[1] TRUE
> is.numeric(y)
[1] FALSE
> is.numeric(data01)
[1] FALSE
> is.character(x) #判断是否为字符
[1] FALSE
> is.character(y)
[1] TRUE
> is.character(data01)
[1] FALSE
> is.vector(x) # 判断是否为向量
[1] TRUE
> is.vector(y)
[1] TRUE
> is.vector(data01)
[1] FALSE
> # 向量x都是数值,可以做运算
> sum(x)
[1] 9
> x <- as.character(x) # 将向量x转化为字符,此时不能再做运算。
> sum(x)
Error in sum(x) : 'type'(character)参数不对

str()函数也可查看具体的一些信息

> str(x)
 chr [1:3] "1" "3" "5"
> str(data01)
'data.frame':	5 obs. of  3 variables:
 $ key: num  5 10 15 20 25
 $ Pa : num  12 17 20 23 30
 $ Pb : num  10 15 21 22 27

4.5 简单数据处理

4.5.1 数据排序

  • 在进行数据分析时,我们有时会根据不同的情况进行排序,R中通过order()函数来对一个数据框进行排序,默认为升序,在排序字段前加一个 “-”号则表示降序。这里只针对数据框排序进行讲解,对于向量的排序返回的值并不是我们实际的排序值,而是返回升序排序后,在原有向量中元素的位置。对于数据框排序order(x, na.last = NA),主要这两个参数,x是需要排序的向量或数据, na.last如果为TRUE,则将数据中缺少的值放在最后;如果为FALSE,则将其放在第一位;如果为NA,则将其删除。
> data01
  key Pa Pb
1   5 12 10
2  10 17 15
3  15 20 21
4  20 23 22
5  25 30 27
> data01[order(-data01$Pa),] #以数据框中Pa进行降序排序
  key Pa Pb
5  25 30 27
4  20 23 22
3  15 20 21
2  10 17 15
1   5 12 10
> data01[order(data01$Pa),1] # 这里以数据框data01的Pa排序,但是只取第一列的数据
[1]  5 10 15 20 25
> data01[3,1] <- NA # 将第3行,1列的数(15)替换为NA
> data01[order(data01$Pa),c("key","Pb")] # 以Pa升序排序,取key 和Pb这两列数据
  key Pb
1   5 10
2  10 15
3  NA 21
4  20 22
5  25 27
> data01[order(data01$key, na.last = TRUE),] #key中有NA,指定na.last = TRUE 则有NA的放在最后
  key Pa Pb
1   5 12 10
2  10 17 15
4  20 23 22
5  25 30 27
3  NA 20 21
> data01[order(data01$key, na.last = NA),] # na.last = NA则删除这一行数据进行排序
  key Pa Pb
1   5 12 10
2  10 17 15
4  20 23 22
5  25 30 27

4.5.2 数据合并,查询,增删

  • 对于有些数据,我们需要通过两张表来获取,因此有时需要将这两张表通过某个共有的变量进行合并,或者有时我们需要新增行数据或者列数据,我们会通过merge()、rbind()、cbind()函数来进行操作:
library(readxl) #载入readxl,来导入我们需要的Excel数据
xl1 <- read_excel("E:\\学习\\text.xls",sheet=1,col_names=TRUE) #读取第一个sheet ,col_names表示含表头
xl2 <- read_excel("E:\\学习\\text.xls",sheet=2,col_names=TRUE)  

在这里插入图片描述

  • 数据合并查询:
# 合并xl1 xl2  通过学号关联合并,all.xl1=all 表示已xl1为主表链接
> xl3 <- merge(xl1,xl2,by ="学号", all.xl1 = all)
> xl3
  学号 姓名 性别 班级 面试 笔试
1  001 张三   男 一班   86   80
2  002 李四   男 二班   78   87
3  003 王五   女 二班   90   90
4  004 赵六   女 一班   68   78
5  005 韩七   男 二班   90   90
# 新增一列总成绩 笔试 0.7 面试0.3,由于excel导入的数据可能不是数值型,这里需要通过as.numeric()函数强制转化成数值型
> xl3$总成绩 <- as.numeric(xl3$面试)*0.7+as.numeric(xl3$笔试)*0.3
> xl3
  学号 姓名 性别 班级 面试 笔试 总成绩
1  001 张三   男 一班   86   80   84.2
2  002 李四   男 二班   78   87   80.7
3  003 王五   女 二班   90   90   90.0
4  004 赵六   女 一班   68   78   71.0
5  005 韩七   男 二班   90   90   90.0
> 

# 取指行,列数据
> xl4 <- xl3[1,] # 通过下标进行取值[x,y] x表示取指定行的数据,y表示取指定列的数据
> xl4
  学号 姓名 性别 班级 面试 笔试 总成绩
1  001 张三   男 一班   86   80   84.2
> xl5 <- xl3[1:3,] # 取1-3行所有数据
> xl5 
  学号 姓名 性别 班级 面试 笔试 总成绩
1  001 张三   男 一班   86   80   84.2
2  002 李四   男 二班   78   87   80.7
3  003 王五   女 二班   90   90   90.0
> xl6 <- xl3[c("姓名","面试","笔试","总成绩")] # 通过c() 来获取向量中对应的数据
> xl6
  姓名 面试 笔试 总成绩
1 张三   86   80   84.2
2 李四   78   87   80.7
3 王五   90   90   90.0
4 赵六   68   78   71.0
5 韩七   90   90   90.0
> 
> xl7 <- xl3[which(xl3$班级=="一班" &xl3$性别=="男"),c("姓名","性别","总成绩")] # 通过which 函数指定哪一个进行筛选
> xl7
  姓名 性别 总成绩
1 张三   男   84.2
> library(dplyr)  #利用sql的方式操作数据框
> xl8 <- select(xl3,"姓名","总成绩"); #通过 select 也可以取数据框中指定的 列数据
> xl8
  姓名 总成绩
1 张三   84.2
2 李四   80.7
3 王五   90.0
4 赵六   71.0
5 韩七   90.0
>#但是对于select 来选取数据有一定的局限性,我们无法进一步选出总成绩≥90的数据,因为对于select 来说必须使用有效的下标向量来子集列
> select(xl3, 1)
  学号
1  001
2  002
3  003
4  004
5  005
> select(xl3, 学号:总成绩) # 查询xl3中学号 到总成绩这一列所有数据
  学号 姓名 性别 班级 面试 笔试 总成绩
1  001 张三   男 一班   86   80   84.2
2  002 李四   男 二班   78   87   80.7
3  003 王五   女 二班   90   90   90.0
4  004 赵六   女 一班   68   78   71.0
5  005 韩七   男 二班   90   90   90.0
> #subset()可以进一步操作
> newdata <- subset(xl3, xl3$面试>85 & xl3$笔试 >= 90, select = c(学号,姓名,笔试)) #select = c(学号,姓名,笔试) 不取连续列
> newdata
  学号 姓名 笔试
3  003 王五   90
5  005 韩七   90
> newdata <- subset(xl3, xl3$面试>85 & xl3$笔试 >= 90, select = 学号:总成绩) #select = 学号:总成绩 取连续列
> newdata
  学号 姓名 性别 班级 面试 笔试 总成绩
3  003 王五   女 二班   90   90     90
5  005 韩七   男 二班   90   90     90
  • 数据删除:
# 原始数据
> xl3
  学号 姓名 性别 班级 面试 笔试 总成绩
1  001 张三   男 一班   86   80   84.2
2  002 李四   男 二班   78   87   80.7
3  003 王五   女 二班   90   90   90.0
4  004 赵六   女 一班   68   78   71.0
5  005 韩七   男 二班   90   90   90.0
# 删除行列数据  
> xl9 <- xl3[,-1] # 删除数据框xl3 中第一列数据 或者xl8 <- xl3[-1]
> xl9
  姓名 性别 班级 面试 笔试 总成绩
1 张三   男 一班   86   80   84.2
2 李四   男 二班   78   87   80.7
3 王五   女 二班   90   90   90.0
4 赵六   女 一班   68   78   71.0
5 韩七   男 二班   90   90   90.0
> xl01 <- xl3[-1,] # 删除数据库xl3 中第一行数据
> xl01
  学号 姓名 性别 班级 面试 笔试 总成绩
2  002 李四   男 二班   78   87   80.7
3  003 王五   女 二班   90   90   90.0
4  004 赵六   女 一班   68   78   71.0
5  005 韩七   男 二班   90   90   90.0
> xl02 <- select(xl3 ,-"面试",-"总成绩")  # 通过select 函数可以取指定列数据,同时用-“指定列” 则可以去掉对应列数据
> xl02
  学号 姓名 性别 班级 笔试
1  001 张三   男 一班   80
2  002 李四   男 二班   87
3  003 王五   女 二班   90
4  004 赵六   女 一班   78
5  005 韩七   男 二班   90
# rm(xl9) # 删除对应数据
# ls(xl5) # 列出对应标题
# ncol(xl3) #查询xl3数据框的列数
# nrow(xl3) #查询xl3数据框的行数
# ls_li <- ls() # 函数ls的功能是显示所有在内存中的对象:只会列出对象名
# ls.str(xl3) #ls.str()将会展示内存中所有对象的详细信息:
#rm(list = ls()) # 将对象列出后传给列表list ,即清空所有已经存在的数据对象
  • 数据新增: 新增行rbind()、新增列cbind() 数据
#新增行数据:rbind()
> adrow <- c("006","刘八","男","一班",77,88,77*0.7+88*0.3); # 先将新增数据定义好,方便后面使用
> xl3_1 <- rbind(xl3, adrow) ## 在xl3数据框中加入一行adrow,加在最后
> xl3_1
  学号 姓名 性别 班级 面试 笔试 总成绩
1  001 张三   男 一班   86   80   84.2
2  002 李四   男 二班   78   87   80.7
3  003 王五   女 二班   90   90     90
4  004 赵六   女 一班   68   78     71
5  005 韩七   男 二班   90   90     90
6  006 刘八   男 一班   77   88   80.3

> xl3_2 <- rbind(xl3[1:2,], adrow ,xl3[3:nrow(xl3),]); # 在xl3数据框 第3行 加入adrow 这一行数据
> xl3_2
   学号 姓名 性别 班级 面试 笔试 总成绩
1   001 张三   男 一班   86   80   84.2
2   002 李四   男 二班   78   87   80.7
3   006 刘八   男 一班   77   88   80.3
31  003 王五   女 二班   90   90     90
4   004 赵六   女 一班   68   78     71
5   005 韩七   男 二班   90   90     90

> xl3_2 <- rbind(xl3[1:2,], adrow ,xl3[3:nrow(xl3),]); # 在xl3数据框 第3行 加入adrow 这一行数据
> xl3_2
   学号 姓名 性别 班级 面试 笔试 总成绩
1   001 张三   男 一班   86   80   84.2
2   002 李四   男 二班   78   87   80.7
3   006 刘八   男 一班   77   88   80.3
31  003 王五   女 二班   90   90     90
4   004 赵六   女 一班   68   78     71
5   005 韩七   男 二班   90   90     90

> xl3_4 <- rbind(adrow,xl3[1:nrow(xl3),]); # 在xl3数据框第1行 加入adrow 这一行数据,注意后面的数据必须都列出来(即原来第一行的数据到最后一行的数据 1:nrow())
> xl3_4
  学号 姓名 性别 班级 面试 笔试 总成绩
1  006 刘八   男 一班   77   88   80.3
2  001 张三   男 一班   86   80   84.2
3  002 李四   男 二班   78   87   80.7
4  003 王五   女 二班   90   90     90
5  004 赵六   女 一班   68   78     71
6  005 韩七   男 二班   90   90     90
# 新增列数据:cbind()
> bz <- c("合格","合格","优秀","合格","优秀")
> xl3_5 <- cbind(xl3,bz); # 在xl3 数据框中加入一行,加在最后一列
> xl3_5 
  学号 姓名 性别 班级 面试 笔试 总成绩   bz
1  001 张三   男 一班   86   80   84.2 合格
2  002 李四   男 二班   78   87   80.7 合格
3  003 王五   女 二班   90   90   90.0 优秀
4  004 赵六   女 一班   68   78   71.0 合格
5  005 韩七   男 二班   90   90   90.0 优秀
> xl3_6 <- cbind(xl3_5[,1:4], c("java","python","R","mysql","oracle"),xl3_5[,5:ncol(xl3_5)]); # 在xl3数据框的第3列增加一列,注意命名,由于没有提前给新增数据命名,那对于数据框来说就会使用所有向量来构成一个列名
> xl3_6
  学号 姓名 性别 班级 c("java", "python", "R", "mysql", "oracle") 面试 笔试
1  001 张三   男 一班                                        java   86   80
2  002 李四   男 二班                                      python   78   87
3  003 王五   女 二班                                           R   90   90
4  004 赵六   女 一班                                       mysql   68   78
5  005 韩七   男 二班                                      oracle   90   90
  总成绩   bz
1   84.2 合格
2   80.7 合格
3   90.0 优秀
4   71.0 合格
5   90.0 优秀
> names(xl3_6) <- c("学号","姓名","性别","班级","专业","笔试","面试","总成绩","备注") # names()函数来指定列名
> xl3_6
  学号 姓名 性别 班级   专业 笔试 面试 总成绩 备注
1  001 张三   男 一班   java   86   80   84.2 合格
2  002 李四   男 二班 python   78   87   80.7 合格
3  003 王五   女 二班      R   90   90   90.0 优秀
4  004 赵六   女 一班  mysql   68   78   71.0 合格
5  005 韩七   男 二班 oracle   90   90   90.0 优秀
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值