13.3 操作数据框
许多数据清理的任务涉及数据框的操作,要把它们转换成相应所需的形式。我们已知可用索引和subset
函数来选择数据框的子集。其他常见任务,包括通过添加其他列(或替换现有列)来扩充数据框、处理缺失值,以及在数据框的宽和长格式之间的转换。以下有几个函数可用于在数据框中添加或替换列。
13.3.1 添加和替换列
假设要为english_monarchs
数据框添加一列来表示统治者执政了多少年,我们可以使用标准的赋值操作符来完成:
english_monarchs$length.of.reign.years <-
english_monarchs$end.of.reign - english_monarchs$start.of.reign
这是可行的,但要反复输入数据框变量名无论是对于输入或阅读来说都太麻烦。with
函数可以通过直接调用变量使之简化。它接受一个数据框2和要计算的表达式作为输入参数:
2或环境。
english_monarchs$length.of.reign.years <- with(
english_monarchs,
end.of.reign - start.of.reign
)
within
函数的工作方式类似,但它会返回整个数据框:
english_monarchs <- within(
english_monarchs,
{
length.of.reign.years <- end.of.reign - start.of.reign
}
)
在此例中within
还需输入更多。当要更改多个列时,它更有用:
english_monarchs <- within(
english_monarchs,
{
length.of.reign.years <- end.of.reign - start.of.reign
reign.was.more.than.30.years <- length.of.reign.years > 30
}
)
也就是说,如果你正在创建或改变某一列,就使用with
;如果你想一次操作多个列,则用within
。
在plyr
包中的mutate
函数采取了另一种方法,它接受新的和更改的列,并把它们当成“名称-值”对 3:
3R基本包中的transform
函数是mutate
函数的早期实现,现已过时。
english_monarchs <- mutate(
english_monarchs,
length.of.reign.years = end.of.reign - start.of.reign,
reign.was.more.than.30.years = length.of.reign.years > 30
)
13.3.2 处理缺失值
在第12章,马鹿数据集显示了用四种不同方式测量得出每头鹿的颅容量。对其中某些而非所有的鹿,会进行第二次测量以测试该技术的可重复性。这意味着某些行会有缺失值。complete.cases
函数告诉我们哪些行没有缺失值:
data("deer_endocranial_volume", package = "learningr")
has_all_measurements <- complete.cases(deer_endocranial_volume)
deer_endocranial_volume[has_all_measurements, ]
## SkullID VolCT VolBead VolLWH VolFinarelli VolCT2 VolBead2 VolLWH2
## 7 C120 346 335 1250 289 346 330 1264
## 8 C25 302 295 1011 250 303 295 1009
## 9 F7 379 360 1621 347 375 365 1647
## 10 B12 410 400 1740 387 413 395 1728
## 11 B17 405 395 1652 356 408 395 1639
## 12 B18 391 370 1835 419 394 375 1825
## 13 J7 416 405 1834 408 417 405 1876
## 15 A4 336 330 1224 283 345 330 1192
## 20 K2 349 355 1239 286 354 365 1243
捷径为na.omit
函数,它能删除数据框中所有带有缺失值的行4:
4na.exclude
与na.omit
的行为一样,两者同存为惯例。
na.omit(deer_endocranial_volume)
## SkullID VolCT VolBead VolLWH VolFinarelli VolCT2 VolBead2 VolLWH2
## 7 C120 346 335 1250 289 346 330 1264
## 8 C25 302 295 1011 250 303 295 1009
## 9 F7 379 360 1621 347 375 365 1647
## 10 B12 410 400 1740 387 413 395 1728
## 11 B17 405 395 1652 356 408 395 1639
## 12 B18 391 370 1835 419 394 375 1825
## 13 J7 416 405 1834 408 417 405 1876
## 15 A4 336 330 1224 283 345 330 1192
## 20 K2 349 355 1239 286 354 365 1243
相反地,如果你的数据框中包含任何缺失值,na.fail
将抛出一个错误:
na.fail(deer_endocranial_volume)
这两个函数也可以对向量进行缺失值删除或者抛出错误,就像在数据框中一样。
注
可以采取统计上可行的多次插补来填补缺失值。这已超出本书的范围,不过我们建议你从
mice
和mix
包开始研究。
13.3.3 在宽和长表格之间进行转换
马鹿数据集包含了以四种不同方式获得的鹿头骨颅容量数据。它的每一列包含了对某种类型的鹿的测量结果。(为简单起见,我们忽略了重复测量的列。)这就是数据框的宽形式:
deer_wide <- deer_endocranial_volume[, 1:5]
从另一个角度看,每一列中的头骨测量数据都是同一类型的东西(即测量值),只是测量的方式不同。因此,另一种表示该数据的方式是:每个鹿都有4行数据,每行有以下几列:一列是和之前一样颅骨的ID(所以每个值将被重复四次),一列为测量值,还有一列用于解释本行所在的测量类型的因子。这就是所谓的数据框的长格式。
R的基础包中reshape
的函数能用于宽和长形式之间的转换。它的功能非常强大,但并不太直观。更好的选择是使用reshape2
包中的功能。
在这个包中可用melt
函数将宽形式转换成长形式5。我们选择SkullID
作为ID列(与其他所有都被归为一次测量):
5术语“melting”及其反义词“casting”均参考自钢铁行业。
library(reshape2)
deer_long <- melt(deer_wide, id.vars = "SkullID")
head(deer_long)
## SkullID variable value
## 1 DIC44 VolCT 389
## 2 B11 VolCT 389
## 3 DIC90 VolCT 352
## 4 DIC83 VolCT 388
## 5 DIC787 VolCT 375
## 6 DIC1573 VolCT 325
或者,使用measure.vars
参数,它显示除了id.vars
列之外的其他所有列。在这种情况下,工作量会变大,但当有很多的ID变量和极少测量变量时,它很有用:
melt(deer_wide, measure.vars = c("VolCT", "VolBead", "VolLWH", "VolFinarelli"))
dcast
函数能把长转换回宽形式,并将结果返回为一个数据框(相关函数acast
返回一个向量、矩阵或数组):
deer_wide_again <- dcast(deer_long, SkullID ~ variable)
我们重构的数据集deer_wide_again
与原来的deer_wide
基本一样,除了它按SkullID
中的字母顺序排序。
注意
电子表格的爱好者可能会注意到,
acast
和dcast
能有效地创建数据透视表。
13.3.4 使用SQL
sqldf
包提供了使用SQL操作数据框的方式。一般情况下,标准R里面的函数都比SQL代码要更简洁、可读性也更好。不过,当你原来的工作背景是数据库,这个包能帮你平滑过渡到R:
install.packages("sqldf")
下例将比较标准R和sqldf
版本的子集查询语句:
library(sqldf)
## Loading required package: DBI
## Loading required package: gsubfn
## Loading required package: proto
## Loading required namespace: tcltk
## Loading required package: chron
## Loading required package: RSQLite
## Loading required package: RSQLite.extfuns
subset(
deer_endocranial_volume,
VolCT > 400 | VolCT2 > 400,
c(VolCT, VolCT2)
)
## VolCT VolCT2
## 10 410 413
## 11 405 408
## 13 416 417
## 16 418 NA
query <-
"SELECT
VolCT,
VolCT2
FROM
deer_endocranial_volume
WHERE
VolCT > 400 OR
VolCT2 > 400"
sqldf(query)
## Loading required package: tcltk
## VolCT VolCT2
## 1 410 413
## 2 405 408
## 3 416 417
## 4 418 NA