本章内容
操纵日期和缺失值
熟悉数据类型的转换
变量的创建和重编码
数据集的排序、合并与取子集
选入和丢弃变量
4.2 创建新变量/对现有变量进行变换
变量名<-表达式
将新变量sumx,meanx整合到原始数据框mydata
mydata <- transform(mydata,
sumx = x1 + x2,
meanx = (x1 + x2)/2)
4.3 重编码:根据同一个变量和/或其他变量的现有值创建新值的过程
例如:
将一个连续型变量修改为一组类别值;
将误编码的值替换为正确值;
基于一组分数线创建一个表示及格/不及格的变量。
逻辑运算符
例子1:将经理人的连续型年龄变量age重编码为类别型变量 agecat(Young、 Middle Aged、Elder)。
- 缺失值处理:将99岁的年龄值重编码为缺失值
leadership$age[leadership$age == 99] <- NA
- 创建新的类别变量
leadership$agecat[leadership$age > 75] <- "Elder"
leadership$agecat[leadership$age >= 55 &
leadership$age <= 75] <- "Middle Aged"
leadership$agecat[leadership$age < 55] <- "Young"
- 也可以写成:
leadership <- within(leadership,{
agecat <- NA
agecat[age > 75] <- "Elder"
agecat[age >= 55 & age <= 75] <- "Middle Aged"
agecat[age < 55] <- "Young" })
函数within()与函数with()类似(见2.2.4节),不同的是它允许你修改数据框。
首先,创 建了agecat变量,并将每一行都设为缺失值。
括号中剩下的语句接下来依次执行。请记住agecat 现在只是一个字符型变量
其他小的应用:
- car包中的recode()函数可以十分 简便地重编码数值型、字符型向量或因子。
- doBy包提供了另外一个很受欢迎的函数 recodevar()。
- R中也自带了cut(),可将一个数值型变量按值域切割为多个区间,并返 回一个因子。
4.4 变量的重命名
- fix(leadership)
- 调用一个交互式的编辑器。然后你单击变量名,然后在弹出的对话框中将其重命名
- 单个重命名
- names(leadership)[2] <- "testDate"
- 批量重命名
- names(leadership)[6:10] <- c("item1", "item2", "item3", "item4", "item5")
- plyr包(已装)中有一个rename()函数,可用于修改变量名;plyr (had.co.nz)
- rename(dataframe, c(oldname="newname", oldname="newname",...))
例子
library(plyr)
leadership <- rename(leadership, c(manager="managerID", date="testDate"))
4.5 缺失值
is.na():检测缺失值是否存在。
- 例子:is.na(leadership$age):检查age这一列
- is.na(leadership[,6:10]):批量检查列
需要注意
第一,缺失值被认为是不可比较 的,即便是与缺失值自身的比较。这意味着无法使用比较运算符来检测缺失值是否存在。例如, 逻辑测试myvar == NA的结果永远不会为TRUE。作为替代,你只能使用处理缺失值的函数(如 本节中所述的那些)来识别出R数据对象中的缺失值。
第二,R 并不把无限的或者不可能出现的数值标记成缺失值。再次地,这和其余像SAS之类 类似的程序处理这类数值的方式所不同。正无穷和负无穷分别用Inf和–Inf所标记。因此5/0返 回Inf。不可能的值(比如说,sin(Inf))用NaN符号来标记(not a number,不是一个数)。若 要识别这些数值,你需要用到is.infinite()或is.nan()。
4.5.1将某些值重编码为缺失值
leadership$age[leadership$age == 99] <- NA
4.5.2 在分析中排除缺失值
含有缺失值的算术表达式和函数的计算结果也是缺失值:由于x中的第3个元素是缺失值,所以y和z也都是NA(缺失值)。
x <- c(1, 2, NA, 3)
y <- x[1] + x[2] + x[3] + x[4]
z <- sum(x)
可以在计算之前移除缺失值并使用剩余 值进行计算:
x <- c(1, 2, NA, 3)
y <- sum(x, na.rm=TRUE)
在使用函数处理不完整的数据时,请务必查阅它们的帮助文档(例如,help(sum)),检查 这些函数是如何处理缺失数据的。
- 通过函数na.omit()移除所有含有缺失值的观测。na.omit()可以删除所有含有缺失数据的行
- 删除所有含有缺失数据的观测(称为行删除,listwise deletion)是处理不完整数据集的若干 手段之一。
4.6 日期值:日期值通常以字符串的形式输入到R中,然后转化为以数值形式存储的日期变量。
- as.Date():来执行这种转换
- as.Date(x, "input_format")
- input_format 如下
mydates <- as.Date(c("2007-06-22", "2004-02-13"))
# 先输入日期符合什么读写规则
myformat <- "%m/%d/%y"
# 再告诉R要依照这个读写规则去写入
leadership$date <- as.Date(leadership$date, myformat)
- Sys.Date()可以返回当天的日期
- 而date()则返回当前的日期和时间。
- 使用函数format(x, format="output_format")来输出指定格式的日期值,并且可以提取日期值中的某些部分
> today <- Sys.Date()
> format(today, format="%B %d %Y")
[1] "November 27 2014"
> format(today, format="%A")
[1] "Thursday"
# format()函数可接受一个参数(本例中是一个日期)并按某种格式输出结果
- 这意味着可以在日期值上执行算术运算。比如计算两个日期间的天数
> startdate <- as.Date("2004-02-13")
> enddate <- as.Date("2011-01-22")
> days <- enddate - startdate
> days
Time difference of 2535 days
- difftime()来计算时间间隔,并以星期、天、时、分、秒来表示。
> today <- Sys.Date()
> dob <- as.Date("1956-10-12")
> difftime(today, dob, units="weeks")
Time difference of 3033 weeks
4.6.1 将日期转换为字符型变量:as.character()
- 字符型数据转换为日期:help(as.Date)和help(strftime)
4.6.2 更多知识
- 关于日期和时间格式的知识:help(ISOdatetime)
- 简化日期处理:lubridate包
- 对日期进行复杂的计算:timeDate包
4.7 类型转换:名为is.datatype()这样的函数返回TRUE或FALSE,而as.datatype()这样的函数则将其 参数转换为对应的类型。
当和第5章中讨论的控制流(如if-then)结合使用时:
is.datatype()这样的函数将成为 一类强大的工具,即允许根据数据的具体类型以不同的方式处理数据。
另外,某些R函数需要接 受某个特定类型(字符型或数值型,矩阵或数据框)的数据,as.datatype()这类函数可以让 你在分析之前先行将数据转换为要求的格式。
例子
> a <- c(1,2,3)
> a
[1] 1 2 3
> is.numeric(a)
[1] TRUE
> is.vector(a)
[1] TRUE
> a <- as.character(a)
> a
[1] "1" "2" "3"
> is.numeric(a)
[1] FALSE
> is.vector(a)
[1] TRUE
> is.character(a)
[1] TRUE
4.8 数据排序:order()
在R中,可以使用order()函数对一个数据框进行排序。
- 默认的排序顺序是升序。在排序变量的 前边加一个减号即可得到降序的排序结果。
例子
# 创建新数据集,其中按年龄排序
newdata <- leadership[order(leadership$age),]
# 按女性到男性,同样性别中按年龄排序
attach(leadership)
newdata <- leadership[order(gender, age),]
detach(leadership)
# 按性别和年龄降序排序
attach(leadership)
newdata <-leadership[order(gender, -age),]
detach(leadership)
4.9 数据集合并
4.9.1 向数据框添加列:merge();cbind()
total <- merge(dataframeA, dataframeB, by="ID")
total <- merge(dataframeA, dataframeB, by=c("ID","Country"))
用cbind()进行横向合并
如果要直接横向合并两个矩阵或数据框,并且不需要指定一个公共索引,那么可以直接使
用cbind()函数:
total <- cbind(A, B)
这个函数将横向合并对象A和对象B。为了让它正常工作,每个对象必须拥有相同的行数,
以同顺序排序。
4.9.2 向数据框添加行:rbind()
纵向合并两个数据框(数据集),请使用rbind()函数:
total <- rbind(dataframeA, dataframeB)
- 两个数据框必须拥有相同的变量,不过它们的顺序不必一定相同。
- 如果dataframeA中拥有 dataframeB中没有的变量,请在合并它们之前做以下某种处理:
- 删除dataframeA中的多余变量;
- 在dataframeB中创建追加的变量并将其值设为NA(缺失)
4.10 数据集取子集
4.10.1 选入(保留)变量
- 数据框中的元素是通过dataframe[row indices, column indices]这样的记号
newdata <- leadership[, c(6:10)]
4.10.2 剔除(丢弃)变量
- 方法1:
myvars <- names(leadership) %in% c("q3", "q4")
newdata <- leadership[!myvars]
(1) names(leadership) 生成了一个包含所有变量名的字符型向量: c("managerID","testDate","country","gender","age","q1", "q2","q3","q4","q5")。
(2) names(leadership) %in% c("q3", "q4") 返回了一个逻辑型向量, names(leadership)中每个匹配q3或q4的元素的值为TRUE,反之为FALSE:c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE)。
(3) 运算符非(!)将逻辑值反转:c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE)。
(4) leadership[c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE)]选择了逻辑值为TRUE的列,于是q3和q4被剔除了。
- 方法2
在知道q3和q4是第8个和第9个变量的情况下,可以使用语句:
newdata <- leadership[c(-8,-9)]
将它们剔除。这种方式的工作原理是,在某一列的下标之前加一个减号(–)就会剔除那一列。
- 方法3:
相同的变量删除工作亦可通过: leadership$q3 <- leadership$q4 <- NULL 来完成。
这回你将q3和q4两列设为了未定义(NULL)。注意,NULL与NA(表示缺失)是不 同的。
4.10.3 选入观测
newdata <- leadership[1:3,]
newdata <- leadership[leadership$gender=="M" &
leadership$age > 30,]
attach(leadership)
newdata <- leadership[gender=='M' & age > 30,]
detach(leadership)
其实就是筛选的过程在 [ ]里完成了,具体的方法和别的一样
希望将研究范围限定在2009年1月1日到2009年12 月31日之间收集的观测上
leadership$date <- as.Date(leadership$date, "%m/%d/%y")
startdate <- as.Date("2009-01-01")
enddate <- as.Date("2009-10-31")
newdata <- leadership[which(leadership$date >= startdate &
leadership$date <= enddate),]
由于as.Date()函数的默认格式就是yyyy-mm-dd,所以你无需在这里提供这个参数
4.10.4 subset():简单方法
例子
newdata<-subset(leadership,age>=35 | age<24,select=c(q1,q2,q3,q4))
newdata<-subset(leadership,gender=="M" & age>25,select=gender:q4)
- 选择所有25岁以上的男性,并保留了变量gender 到q4(gender、q4和其间所有列)
4.10.5 随机抽样:sample()
mysample <- leadership[sample(1:nrow(leadership), 3, replace=FALSE),]
sample()函数中:
- 第一个参数是一个由要从中抽样的元素组成的向量。在这里,这个向量 是1到数据框中观测的数量,
- 第二个参数是要抽取的元素数量
- 第三个参数表示无放回抽样。
sample()函数会返回随机抽样得到的元素,之后即可用于选择数据框中的行。
其他
R中拥有齐全的抽样工具,包括抽取和校正调查样本(参见sampling包)以及分析复杂调 查数据(参见survey包)的工具。其他依赖于抽样的方法,包括自助法和重抽样统计方法,详 见第12章。
4.11 使用SQL语句操作数据框:sqldf()
你可以使用sqldf()函数 在数据框上使用SQL中的SELECT语句。
例子:从数据框mtcars中选择所有的变量(列),保留那些使用化油器(carb)的车型(行),按照mpg对车型进行了 升序排序,并将结果保存为数据框newdf。参数row.names=TRUE将原始数据框中的行名延续到了新数据框中
- sqldf("sql语句",row.names=TRUE)
library(sqldf)
newdf<-sqldf("select * from mtcars where carb=1 order by mpg",row.names = TRUE)
newdf