R语言之基本包

文章和代码已经归档至【Github仓库:https://github.com/timerring/dive-into-AI 】或者公众号【AIShareLab】回复 R语言 也可获取。

用 R 基本包

在实际的数据分析中,分析者往往需要花费大量的精力在数据的准备上,将数据转换为分析所需要的形式。遗憾的是,大多数统计学教材很少涉及这一重要问题。整理数据是统计学的任务之一。我们开始关注 R 中最常用的数据格式——数据框的基本操作。我们将首先使用基本包处理数据框。

先加载 epiDisplay 包里的一个小型数据集 Familydata

library(epiDisplay)
data("Familydata")

1.查看数据框里的内容

如果数据框较小,比如本例(只有 6 个变量,11 条记录),只需输入数据框名即可查看其全部内容,这等价于调用函数 print( ) 显示对象的内容。

# 输入数据框名即可查看其全部内容,这等价于调用函数 print( ) 显示对象的内容。
Familydata
# 用函数 `head( )` 只显示其前几行
head(Familydata)
# 用函数 `tail( )` 显示其最后几行
tail(Familydata)
# 可以加参数指定到底几行
tail(Familydata,7) # 显示尾7行

# 列出所有变量名(列名)
names(Familydata)

另一个可以用来方便地探索数据框结构的函数是 str( )

str(Familydata)

# ==============显示结果=============
# 首先给出了对象的类型(这里是数据框“data.frame”)、观测数和变量的个数;
'data.frame':    11 obs. of  6 variables:
# 接着给出了数据框中每个变量的变量名和类型,以及变量的前几个取值
 $ code : chr  "K" "J" "A" "I" ...
 $ age  : int  6 16 80 18 69 72 46 42 58 47 ...
 $ ht   : int  120 172 163 158 153 148 160 163 170 155 ...
 $ wt   : int  22 52 71 51 51 60 50 55 67 53 ...
 $ money: int  5 50 100 200 300 500 500 600 2000 2000 ...
 # 对于因子型变量还给出了因子的水平;
 $ sex  : Factor w/ 2 levels "F","M": 1 2 2 1 1 1 1 1 2 1 ...
 # 最后给出了数据框的一些属性:
 # 数据标签(“datalabel”)
 - attr(*, "datalabel")= chr "Anthropometric and financial data of a hypothetical family"
 - # 数据建立时间(“time.stamp”)
 - attr(*, "time.stamp")= chr "23 Nov 2006 17:15"
 - attr(*, "formats")= chr [1:6] "%9s" "%8.0g" "%8.0g" "%8.0g" ...
 - attr(*, "types")= int [1:6] 128 98 105 98 105 108
 # 变量标签(“var.labels”)
 - attr(*, "val.labels")= chr [1:6] "" "" "" "" ...
 - attr(*, "var.labels")= chr [1:6] "" "Age(yr)" "Ht(cm.)" "Wt(kg.)" ...
 # 版本号(“version”)
 - attr(*, "version")= int 7
 - attr(*, "label.table")=List of 6
  ..$ sex1: Named num [1:2] 1 2
  .. ..- attr(*, "names")= chr [1:2] "F" "M"
  ..$     : NULL
  ..$     : NULL
  ..$     : NULL
  ..$     : NULL
  ..$     : NULL

这些属性可以增强用户对数据集的理解。要想显示数据框属性的全部信息,可以使用 attributes( ) 函数,该函数的输出是一个列表。

attributes(Familydata)
# ================== 输出 ======================
$names
'code''age''ht''wt''money''sex'
$row.names
1234567891011
$class
'data.frame'
$datalabel
'Anthropometric and financial data of a hypothetical family'
$time.stamp
'23 Nov 2006 17:15'
$formats
'%9s''%8.0g''%8.0g''%8.0g''%8.0g''%8.0g'
$types
1289810598105108
$val.labels
'''''''''''sex1'
$var.labels
'''Age(yr)''Ht(cm.)''Wt(kg.)''Pocket money(B.)'''
$version
7
$label.table
$sex1
F1M2
[[2]]
NULL
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
[[6]]
NULL

也可以修改和自定义这些属性。例如,从上面的输出可以看到,第一个变量和最后一个变量没有定义标签。现在为这两个变量添加标签:

attr(Familydata, "var.labels")[1] <- "Identification number"
attr(Familydata, "var.labels")[6] <- "Gender"
attributes(Familydata)$var.labels
# 'Identification number''Age(yr)''Ht(cm.)''Wt(kg.)''Pocket money(B.)''Gender'

给变量添加标签能帮助我们更好地理解变量的含义。此外,后面用到的 epiDisplay 包里有些函数的输出还能直接使用这些变量标签。

2.选取数据框的子集

与矩阵类似,我们可以用索引下标的方式选取数据框的子集。

# 选择数据框 Familydata 的第 3 列
Familydata[, 3]
# 也可以使用$变量名的方式
Familydata$ht

# 要提取一个以上的变量,可以使用变量的索引号或名字。例如,只显示变量ht、wt 和 sex 的前 3 条记录,可以输入:
Familydata[1:3, c(3, 4, 6)]
# 等价于
Familydata[1:3, c("ht", "wt", "sex")]

下标中的索引还可以是一个条件语句。例如,要选择性别为女性的数据,可以输入:

Familydata[Familydata$sex == "F", ] # 注意逗号跟双等号

另一种选择数据框的子集的方法是使用 subset( ) 函数。

subset(Familydata, sex == "F")
# 若只选择女性中的变量 ht 和 wt
subset(Familydata, sex == "F", select = c(ht, wt))
注意,该命令只是选择一个子集来显示,不会对原来的数据框产生任何影响。如果还要进一步使用该子集,需要把它存为一个新的对象。

在机器学习领域,经常需要从数据集里随机抽取一部分样本。例如,我们想把一个大的数据集随机分成两份,其中一份用于构建预测模型,另一份用于验证模型的预测精度。函数 sample( ) 可用于随机抽样,下面的命令从数据框 Familydata 里随机抽取一个大小为 3 的样本:

sample.rows <- sample(1:nrow(Familydata), size = 3, replace = FALSE)
sample.rows
# 5 4 1

函数 sample( ) 中的第一个参数是一个由要从中抽样的元素组成的向量,在这里是从 1 到数据框中的总观测数;第二个参数 size 是要抽取的元素的数量;第三个参数 replace 用于设定是否放回抽样,默认为 FALSE(不放回抽样)。

函数 sample( ) 的返回值可用于选择数据框中的行。由于随机种子数的不同,每次运行得到的结果很可能不一样。

3.将数据框按照某个变量的值排序:order( )

有时我们想将数据框按照某个变量的值的大小进行排序显示,这可以借助函数 order( ) 实现。例如,将数据框 Familydata 以变量 age 的值从小到大显示,可以使用下面的命令:

# ,前表示条件 ,后表示显示的列
Familydata[order(Familydata$age), ] # 默认升序
# 降序写法
Familydata[order(Familydata$age, decreasing = TRUE), ]
# 等价于age取反结果
Familydata[order(-Familydata$age), ]

4.查找和删除重复数据:duplicated( )

原始数据集里经常会有重复的行。如果不是重复测量的数据,数据集的每一行应该是某一个对象的观测,而且数据集里通常有一个用于识别个体的变量(比如 id)。

数据集 Familydata 中的变量 code 就是个体识别号,下面检查该变量有无重复值:

duplicated(Familydata$code)
# FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
# 函数 duplicated( ) 的返回值是逻辑值 TRUE 或 FALSE,这里全为 FASLE,表明变量 code 没有重复值。

如果数据框的行数较多,逐一查看这些逻辑值会很麻烦。此时,可以将函数 any( ) 作用于函数 duplicated( ) 的输出结果:

any(duplicated(Familydata$code))
# FALSE

或者使用函数 table( ),还能得到重复值的个数:

table(duplicated(Familydata$code))
# FALSE 
# 11

删除重复行

为了阐明怎样删除重复的行,下面建立一个数据框 Familydata1,将原数据框 Familydata 的第 2 行添加在其第 12 行:

Familydata1 <- Familydata
Familydata1[12, ] <- Familydata[2, ]
Familydata1

使用函数 which( ) 可以找出变量 code 的重复值所在的行:

which(duplicated(Familydata1$code))

然后,删除重复的行:

# 将不重复的新建对象即可
unique.code.data <- Familydata1[!duplicated(Familydata1$code), ]
unique.code.data

identical 查看对象是否完全一样

# 用identical查看两个对象是否完全一样
identical(unique.code.data, Familydata)
# TRUE

5.在数据框中添加和删除变量

在处理数据框时,我们经常需要创建新的变量并把它添加到现有的数据框中。例如,建立一个新的变量 log10money,其值等于变量 money 以 10 为底的对数。最直接地,可以输入:

Familydata$log10money <- log10(Familydata$money)
# 或者可以使用 `transform( )` 函数:
Familydata <- transform(Familydata, log10money = log10(money))
names(Familydata)
# 'code''age''ht''wt''money''sex''log10money'

与添加变量相反,如果想从数据框中删除一个变量,只需在方括号内下标号的前面添加一个减号。例如:

Familydata[, -7]

请注意,该命令只显示所需的子集,对数据框本身不会产生影响。

但是赋一个空值(NULL)给数据框中的变量等同于删除该变量,并且是会永久删除数据框中的变量:

Familydata$log10money <- NULL
colnames(Familydata)

6.把数据框添加到搜索路径

在前面查看和使用数据框中的变量时,我们需要在变量名前面加上数据框名和符号 $。这种方式有时候会显得比较烦琐,尤其是数据框和变量的名字都很长的时候。此时,函数 attach( ) 或者函数 with( ) 可以用来简化代码。

函数 attach( ) 可以将数据框添加到搜索路径中。输入以下命令:

attach(Familydata)

然后用函数 search( ) 查看搜索路径中的所有对象:

search()
#'.GlobalEnv''Familydata''package:epiDisplay''package:nnet''package:MASS''package:survival''package:foreign''package:repr''jupyter:irkernel''package:stats''package:graphics''package:grDevices''package:utils''package:datasets''package:methods''Autoloads''package:base'

现在搜索路径中的第二个位置存放了数据框 Familydata。由于数据框已经在搜索路径中了,而变量 age 又在该数据框里,所以现在可以直接使用变量 age 了。

summary(age)
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#    6.00   30.00   47.00   45.73   63.50   80.00 

把一个数据框放入搜索路径类似于使用函数 library( ) 加载一个包。调入搜索路径的数据框和加载的包都会被自动读入 R,并一直存放在内存中直至它们被移出(detach( ))。

使用函数 attach( ) 虽然会在输入代码时带来一些便利,但同时也会带来一些问题。例如,重复加载数据框可能会最终导致系统资源过度负荷。另外,如果全局环境中或多个数据框中有相同的变量名,容易使用户产生混淆。因此,有些 R 的使用者尽量避免使用函数 attach( ),而使用函数 with( )

datasets 包里的数据集 infert 为例:

with(infert, summary(age))
#  Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
#  21.00   28.00   31.00   31.50   35.25   44.00 

函数 with( ) 的局限性在于,对于多次使用数据框,我们必须重复使用函数 with( )。此外,赋值仅在此函数内部生效,例如:

with(infert, {
  m <- mean(age)}
  )
m 
# ERROR:object 'm' not found

选择哪一种数据处理方式取决于分析者的偏好。例如《R 语言医学数据分析实战》推荐的做法是:

  1. 在开启一个新的分析项目时,首先使用命令 rm(list = ls( )) 从 R 工作环境中清除所有对象;
  2. 在分析过程中用函数 detach( ) 将不再需要使用的数据框从搜索路径中移出;
  3. 不要定义与已经存在于搜索路径中的数据框同名的新对象;

你可能感兴趣的:(r)