Chapter4 基本数据管理
-
一个示例
创建leadership数据库
manager <- c(1,2,3,4,5) date <- c("10/24/08","10/28/08","10/1/08","10/12/08","5/1/09") country <- c("US","US","UK","UK","UK") gender <- c("M","F","F","M","F") age <- c(32,45,25,39,99) q1 <- c(5,3,3,3,2) q2 <- c(4,5,5,3,2) q3 <- c(5,2,5,4,1) q4 <- c(5,5,5,NA,1) q5 <- c(5,5,2,NA,1) leadership <- data.frame(manager,date,country,gender,age,q1,q2,q3,q4,q5,stringsAsFactors = F)
4.2 创建新变量
在典型的研究项目中,你可能需要创建新变量或者对现有的变量进行变换。通过 变量名<- 表达式 来完成。
算术运算符
+,-,*,/ 加减乘除
^ or ** 求幂
x%%y 求余(x mod y).5%%2的结果为1
x%/%y 整数除法。5%/2% 的结果为2
提取旧变量并创建新变量的三种方式
mydata <- data.frame(x1=c(2,2,6,4),
x2=c(3,4,2,8))
##方式一,使用$创建新变量。
mydata$sumx <- mydata$x1 + mydata$x2
mydata$meanx <- (mydata$x1 + mydata$x2)/2
View(mydata)
##方式二
rm(mydata) #移除mydata之前赋值的信息
attach(mydata)
mydata$sumx <- x1+x2
mydata$meanx <- (x1+x2)/2
detach(mydata)
##方式三
rm(mydata)
mydata <- transform(mydata,
sumx=x1+x2,
meanx=(x1+x2)/2)
作者认为更倾向于第三种方式,即transform()函数,简化了按需创建新变量并将其保存到数据框中的过程。
4.3 变量的重编码
重编码涉及根据同一个变量或其他变量的现有值创建新值的过程。
目标:
1.将一个连续型变量修改为一组类别值;
2.将误编码的值替换为正确值;
3.基于一组分数线创建一个表示及格/不及格的变量。
逻辑运算符
< 小于
<= 小于或等于
大于
.> = 大于或等于
== 严格等于
!= 不等于
!x 非x
x|y x或y
x & y x和y
isTRUE(x) 测试x是否为TRUE
将示例中的leadership数据几种经理人的连续型年龄变量age重编码为类别型变量agecat(Young,MiddleAged,Elder).将连续型变量变为类别型变量
#将99岁的年龄值重编码为缺失值
leadership$age[leadership$age == 99] <- NA
#语句variable[condition] <- expression 将仅在condition 的值为TRUE时执行赋值。接下来创建agecat变量。
leadership$agecat[leadership$age > 75] <- "Elder"
leadership$agecat[leadership$age >= 55 &
leadership$age <=75 ] <- "Middle Aged"
leadership$agecat[leadership$age < 55] <- "Young"
View(leadership)
上述代码的更紧凑版本。
leadership <- within(leadership,{
agecat <- NA
agecat[age>75] <- "Elder"
agecat[age>=55 & age <= 75] <- "Middle Aged"
agecat[age<55] <- "Young"
})
函数within()与函数with()类似,不同的是它允许你修改数据框。首先创建了agecat变量,并将每一行都设为缺失值,括号中剩下的语句接下来依次执行,agecat此时只是一个字符型变量。
4.4 变量的重命名
4.4.1.交互式的方式
假设你希望将变 量名manager修改为managerID,并将date修改为testDate,那么可以使用语句
fix(leadership)
4.4.2编程的方式
#将第二列的名字改变
names(leadership)[2] <- "testDate"
#重命名q1到q5为item1到item5
names(leadership)[6:10] <- c("item1","item2","item3","item4","item5")
#names()默认更改列名,若改行名则用row.names()
row.names(leadership)[2] <- "testDate"
4.5 缺失值
在任何规模的项目中,数据都可能由于未作答问题、设备故障等原因造成不完整,在R中,缺失值以符号NA(not available)表示。与SAS等程序不同,R中字符型和数值型数据使用的缺失值符号是相同的。
函数is.na()允许你检测缺失值是否存在。
y <- c(1,2,3,NA)
is.na(y)
将返回c(FALSE FALSE FALSE TRUE)
#is.na会返回一个相同大小的对象,如果某个元素是缺失值,相应的位置将被改写成TRUE,不是缺失值的位置则为FALSE。
#应用is.na到leadership上
is.na(leadership[,6:10])
q1 q2 q3 q4 q5
[1,] FALSE FALSE FALSE FALSE FALSE
[2,] FALSE FALSE FALSE FALSE FALSE
[3,] FALSE FALSE FALSE FALSE FALSE
[4,] FALSE FALSE FALSE TRUE TRUE
[5,] FALSE FALSE FALSE FALSE FALSE
处理缺失值时要主要两件事,第一,缺失值被认为是不可比较的,即便是与缺失值自身的比较。这意味着无法使用比较运算符来检测缺失值是否存在。第二,R并不能把无限的或者不可能出现的数值标记成缺失值。正负无穷分别用Inf和-Inf所标记,因此5/0返回Inf,不可能的值(如sin(Inf))用NaN(not a number)来标记。
4.5.1 重编码某些值为缺失值
如4.3所述,可以用赋值语句将某些值重编码为缺失值。
4.5.2 在分析中排除缺失值
确定了缺失值的位置后,需要在进一步分析数据之前以某种方式删除这些缺失值,原因是含有缺失值的算术表达式和函数的计算结果也是缺失值。
#举例
x <- c(1,2,NA,3)
y <- x[1]+x[2]+x[3]+x[4]
z <- sum(x) #用is.na 判断,y z均为NA
#通过na.rm=TRUE在计算之前移除NA并使用剩余值进行计算
x <- c(1,2,NA,3)
y <- sum(x,na.rm = T) #返回y的值为6
#使用na.omit()删除不完整的观测,含有NA的行被移除
newdata <- na.omit(leadership)
View(newdata)
删除所有含有NA的观测(称为行删除,listwise deletion)是处理不完整数据集的若干手段之一。如果只有少数NA或者NA仅集中于一小部分观测中,行删除不失为解决NA的一种优秀方法。但如果NA遍布于数据之中,或者一小部分变量中包含大量的NA,行删除可能会提出相当比例的数据。更优秀的处理方法在18章。
4.6 日期值
日期值通常以字符串的形式输入到R中,然后转化为以数值形式存储的日期变量。函数as.Date()用于执行这种转化,其语法为as.Date(x,"input_format"),其中x是字符型数据,input_format则给出了用于读入日期的适当格式。
%d 数字表示的日期,如01-31
%a 缩写的日期名,如Mon
%A 非缩写星期名,如Monday
%m 月份(00-12),如00-12
%b 缩写的月份,如Jan
%B 非缩写的月份,如January
%y 两位数的年份,如07
%Y 四位数的年份,如2007
日期值的默认输入格式为yyyy-mm-dd。语句:
#将默认格式的字符型数据转换为对应日期
strDates <- c("01/05/1965","08/16/1975")
dates <- as.Date(strDates,"%m/%d/%Y")
View(dates)
????
myformat <- "%m/%d/%y"
leadership$date <- as.Date(leadership$date,myformat)
使用指定格式读取字符型变量,并将其作为一个日期变量替换到数据框中。
Sys.Date() ##返回当天的日期
date() ##返回当前的日期和时间
使用函数format(x,format="output_format")来输出指定格式的日期值,并且可以提取日期值中的某些部分。
today <- Sys.Date()
format(today,format="%B %d %Y")
format(today,format="%A")
在日期值上执行算术运算
startdate <- as.Date("2004-02-13")
enddate <- as.Date("2011-01-22")
days <- enddate - startdate
days #得到中间相差多少天
#计算有几周大,最后给的问题是生于周几,没完成
today <- Sys.Date()
dob <- as.Date("1956-10-12")
difftime(today,dob,units = "weeks")
4.6.1 将日期转换成字符型变量
#使用as.character()将日期值转换成字符型
strDates <- as.character(dates)
class(strDates)
4.6.2 更进一步
4.7 类型转换
判断 转换
is.numeric() as.numeric()
is.character() as.character()
is.vector() as.vector()
is.matrix() as.matrix()
is.data.frame() as.data.frame()
is.factor() as.factor()
is.logical() as.logical()
名为is.datatype()这样的函数返回T或F,而as.datatype()则将其他参数转换为对应的类型。
4.8 数据排序
在R中,可以使用order()函数对一个数据框进行排序,默认的排序顺序是升序,在排序变量的前面加一个减号即可得到降序的排列结果。
#创建一个新的数据集,各行按经理人的年龄升序排序。
newdata <- leadership[order(leadership$age),]
View(newdata)
#将各行依女性到男性,同样性别中按年龄升序排序。
attach(leadership)
newdata <- leadership[order(gender,age),]
detach(leadership)
View(newdata)
#将各行依经理人的性别和年龄降序排序
attach(leadership)
newdata <- leadership[order(gender,-age),]
detach(leadership)
View(newdata)
4.9 数据集的合并
4.9.1 向数据框添加列
要横向合并两个数据框(数据集),请使用merge()函数。在多数情况下,两个数据框是通过一个或者多个共有变量进行联结的(即一种内联结,inner join)。如:
#将dataframeA 和dataframeB按照ID进行了合并
total <- merge(dataframeA,dataframeB,by="ID")
#将两个数据框按照ID和Country进行了合并
total <- merge(dataframeA,dataframeB,by=c("ID","Country"))
#如果要直接横向合并两个矩阵或者数据框,并且不需要指定一个公共索引,可以直接使用cbind()函数,前提是每个对象必须拥有相同的行数,以同顺序排序。
total<- cbind(A,B)
4.9.2 向数据框添加行
要想纵向合并两个数据框(添加行),使用rbind()函数,两个数据框必须拥有相同的变量,不过它们的顺序不必一定相同,如果dataframeA中拥有dataframeB中没有的变量,在合并前做如下处理:1.删除dataframeA中的多余变量;2.在dataframeB中创建追加的变量并将其值设为NA
total <- rbind(dataframeA,dataframeB)
4.10 数据集取子集
4.10.1 选入(保留)变量
对数据框中的元素,通过dataframe[row indices,column indices]来访问
#从leadership数据框中选择了6-10列,并将它们保存到了数据框newdata中,将行下标留空表示默认选择所有行。
newdata <- leadership[,c(6:10)]
#与上述等价,引号中的变量名充当了列的下标,因此与上述选择的列是相同的
myvars <- c("q1","q2","q3","q4","q5")
newdata <- leadership[myvars]
# 也可以写为
myvars <- paste("q",1:5,sep = "")
newdata <- leadership[myvars]
View(newdata)
4.10.2 剔除(丢弃)变量
##names(leadership)提取包含所有变量名的字符型向量,%in% c("q3","q4")返回一个逻辑向量,匹配q3或q4的元素值为T,反之为F。
myvars <- names(leadership) %in% c("q3","q4")
#[!myvars]将逻辑值反转,进而选择没有q3或q4的列
newdata <- leadership[!myvars]
View(newdata)
##在知道q3和q4是8th和9th变量的情况下,每一列的下标之前加一个减号表示剔除那一列。
newdata <- leadership[c(-8,-9)]
剔除工作还可以通过如下语句删除。注意NULL与NA(缺失)不同
leadership$q3 <- leadership$q4 <- NULL
4.10.3 选入观测
选择所有30岁以上的男性。方式一:
newdata <- leadership[leadership$gender=="M" & leadership$age > 30,]# [leadership$gender=="M" &leadership$age > 30,]生成TRUE的逻辑比较值,并提取所有行
方式二:使用attach()
,就不必再变量名前加上数据框名称了
attach(leadership)
newdata <- leadership[gender=='M' & age > 30,]
detach(leadership)
View(newdata)
将研究范围限定在某一日期范围的观测上
#使用mm/dd/yy将作为字符值读入的日期转换为日期值
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),]
4.10.4 subset()函数
subset()函数大概是选择变量和观测最简单的方法了。
#1 选择所有age值大于等于35或age值小于24的行,保留了变量q1到q4。若去掉select()则全都保留。
newdata <- subset(leadership,age >=35 | age <24,select = c(q1,q2,q3,q4))
View(newdata)
#2 选择所有25岁以上的男性,并保留了变量gender到q4之间的所有列。
newdata <- subset(leadership,gender=="M" & age >25,select = gender:q4)
View(newdata)
4.10.5 随机抽样
sample()函数能够让你从数据集中(有放回或无放回地)抽取大小为n的一个随机样本。
#从leadership数据集中随机抽取一个大小为3的样本
mysample <- leadership[sample(1:nrow(leadership),3,replace = F),]
View(mysample)
sample()
函数中,第一个参数是一个由要从中抽样的元素组成的向量,在这里,这个向量 是1到数据框中观测的数量;第二个参数是要抽取的元素数量,第三个参数表示无放回抽样。