共计 5993 个字符,预计需要花费 15 分钟才能阅读完成。
文章和代码曾经归档至【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 语言医学数据分析实战》举荐的做法是:
- 在开启一个新的剖析我的项目时,首先应用命令
rm(list = ls()
) 从 R 工作环境中革除所有对象; - 在剖析过程中用函数
detach()
将不再须要应用的数据框从搜寻门路中移出; - 不要定义与曾经存在于搜寻门路中的数据框同名的新对象;