在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
如同列夫托尔斯泰所说的那样:“幸福的家庭都是相似的,不幸的家庭各有各的不幸”,糟糕的恶心的数据各有各的糟糕之处,好的数据集都是相似的。一份好的,干净而整洁的数据至少包括以下几个要素: 1、每一个观测变量构成一列
每一列就是观测的指标:花瓣长度,花瓣宽度,萼片长度,萼片宽度,种类;每一行就是一株鸢尾花的观测值,构成整张表的元素就是四个数值变量,一个分类分类变量。 然而出于排版的考虑我们抓下来的数据往往不是那么的友好,比如说我们可以看到的数据通常是这样的:
而不是:
当然,除了这种把列表每一列代表一些数值这种情况外,还有多个变量储存为一列(比如列表不仅以"<10k","10k-50k","50k-100k"做表头,甚至还加上性别信息"m<10k","m10k-50k","m50k-100k","f<10k","f10k-50k","f50k-100k",其中m代表男性,f代表女性),还有更过分的将列表的变量不仅储存在列中,行中也有统计变量。 面对这些不好的table,我们首先要做的就是数据管理,将数据整理为一个干净的数据集。 数据管理按照en:DAMA的定义:“数据资源管理,致力于发展处理企业数据生命周期的适当的建构、策略、实践和程序”。这是一个高层而包含广泛的定义,而并不一定直接涉及数据管理的具体操作(如关系数据库的技术层次上的管理)。我们这里主要讲述对于数据的变量命名与数据的合并,旨在方便数据共享。 数据管理首先要做的就是大致上了解你的数据,比如有什么样的变量,每一行大致长成什么样,最常用的就是head(),tail().
我们以UCI的Human Activity Recognition Using Smartphones Data Set 为例来看看数据是如何变成一个基本符合要求的数据。这个数据我们已经下载下来了,其中关于数据的详细信息可以参阅read me文档,由于UCI的数据通常都是一个基本合乎规范的数据集(主要是指它的数据集的变量名都是以V1,V2来命名的)加上一个code book。那么我们看看各个数据的名称(在feature文件里)
我们可以看到各个特征的名称直接标在数据上是非常不友善的,我们为了让他具有可读性,我们以展示在我们眼前的6个数据为例: variablename <- head(name)# 将标签中的大写字母转为小写,我们这里没有所以不再赋值,如果需要全变为大写,可以使用touppertolower(variablename$V2)
# 将变量名分离成3部分splitNames <- strsplit(variablename$V2, "-")splitNames[[1]]
# 将变量名合成有意的名称named <- function(x) { rr <- paste(x[2], x[1], "-", x[3], sep = "")
chartr("()", "of", rr)
}
sapply(splitNames, named)
用这样的名字给数据集命名就感觉舒服多了,我们将一些R中对字符串常用的操作函数总结如下,方便我们对数据名称的修改:
变量的名称建议满足如下要求:
字符型变量应该满足:
接下来我们讨论数据集的合并,主要使用函数merge。 df1 <- data.frame(id = sample(1:10), reviewer_id = sample(5:14), time_left = sample(1321:1330),
x = rnorm(10))df2 <- data.frame(id = sample(1:10), answer = rep("B", 10), time_left = sample(321:330),
y = rnorm(10))
head(df1, n = 3)
head(df2, n = 3)
merge函数调用格式为:
参数说明:
仔细观察下面3个例子你就会发现其中的奥秘: mergedData <- merge(df1,df2,by.x="reviewer_id",by.y="id",all=TRUE)
head(mergedData)
mergedData <- merge(df1,df2,by.x="id",by.y="id",all=TRUE)
head(mergedData)
mergedData2 <- merge(df1,df2,all=TRUE)
head(mergedData2)
在plyr包中还提供了join,join_all,arrange等函数来实现表的连接,但我想merge这个函数已经足够用了,所以我们不在多说。当然,在极少数特别好的情况下(比如列的变量是一致的,或者行的观测个体是一致的时候)rbind,cbind也是有用的。 有些时候我们会遇到一些特殊的字符串:日期。R中提供了各式各样的函数来处理时间: Sys.setlocale("LC_TIME", "C")
x <- c("1jan1960", "2jan1960", "31mar1960", "30jul1960")z <- as.Date(x, "%d%b%Y")
format(z, "%a %b %d")
weekdays(z)
julian(z)
transform(z, weekend = as.POSIXlt(z, format = "%Y/%m/%d")$wday %in% c(0, 6))
数据操作与整合说到数据操作,这也是一个十分宽泛的话题,在这里我们就以下4个方面进行介绍:
然而在进行这一切之前首先要做的就是了解你的数据,我们以世界银行的数据Millennium Development Goals为例,来一步步演示如何进行数据操作: if (!file.exists("C:/Users/yujun/Documents/MDG_Data.csv")) {
download.file("http://databank.worldbank.org/data/download/MDG_csv.zip","F:/MDG.zip")
unzip("F:/MDG.zip")
}MDstats<-read.csv("C:/Users/yujun/Documents/MDG_Data.csv")
首先先来看一部分数据: head(MDstats)
tail(MDstats)
我们显然发现了这不是一个tidy data,那么我们先将其变换为我们喜欢的tidy data,之后再看看数据摘要及数据集各单元的属性:
我们可以看看各个数值数据的分位数: quantile(MDstatsMelt$value,na.rm=TRUE)
看看各个国家的统计数据有多少: table(MDstatsMelt$countrycode)
看看缺失值: sum(is.na(MDstatsMelt$value)) #总的缺失值
colSums(is.na(MDstatsMelt)) #每一列的缺失值
# 如果我们用回tidy前的数据集,那么这个函数会显得比较有用colSums(is.na(MDstats))
# 等价的处理方式stat <- function(x) {
sum(is.na(x))
}
tapply(MDstatsMelt$value, MDstatsMelt$year, stat)
统计某个国家的统计数据占总统计数目的多少 table(MDstatsMelt$countryname %in% c("China"))
prop <- table(MDstatsMelt$countryname %in% c("China"))[2]/sum(table(MDstatsMelt$countryname %in% c("China")))prop
看看数据集的大小: object.size(MDstatsMelt)
print(object.size(MDstatsMelt),units="Mb")
至此,我们可以说我们对数据有了一定的了解。另外值得一提的是,对于某些特定的数据,也许xtabs,ftable是有用的。 数据的筛选要提取相应内容的数据,最为常用的就是提取相应元素,比如提取某个元素,提取某一行,某一列。我们通过下面下面的例子来学习: data<-data.frame(a=sample(1:10),b=rep(c("a","b"),each=5),cdf=rnorm(10))data
#提取相应元素data[2,1]
data[[1]][[2]]
data[[c(1,2)]]
data$a[2]
#提取某一列data[[3]]
data$cdf
data$c
data[["c"]]
data[["c", exact = FALSE]]
数据的筛选还有一个最为常用的的就是移除缺失值: data<-data.frame(a=c(sample(1:5),NA,NA,sample(6:10)),b=c(rep(c("a","b"),each=5),NA,NA),cdf=rnorm(12))data
good <- complete.cases(data)data[good, ]
bad <- as.data.frame(is.na(data))data[!(bad$a|bad$b|bad$c),]
数据筛选有时是为了获得符合条件的数据: X <- data.frame("var1"=sample(1:5),"var2"=sample(6:10),"var3"=sample(11:15))X <- X[sample(1:5),]; X$var2[c(1,3)] = NAX
X[(X$var1 <= 3 & X$var3 > 11),]
subset(X,(X$var1 <= 3 & X$var3 > 11))
X[(X$var1 <= 3 | X$var3 > 15),]
X[which(X$var1 <= 3 | X$var3 > 15),]
对于取子集的函数subset,在帮助文档中有一段warning是值得我们注意的:“This is a convenience function intended for use interactively. For programming it is better to use the standard subsetting functions like [, and in particular the non-standard evaluation of argument subset can have unanticipated consequences." 数据的变换常见的数据变换函数有:
除此以外,我们还经常对数据加标签,以期在回归中测量其效应。我们以MASS包的shuttle数据集为例,想知道不同类型的风(wind)是否需要使用不同的装载机(use),这里我们希望将head wind标记为1,auto use也记为1,我们可以按照如下办法设置虚拟变量: library(MASS)
data(shuttle)
head(shuttle)
## Make our own variables just for illustrationshuttle$auto <- 1 * (shuttle$use == "auto")shuttle$headwind <- 1 * (shuttle$wind == "head")
head(shuttle)
当然对于因子类型变量,relevel函数在线性模型的分析中也是能取得等价效果的。 有些时候,我们还常常将连续数据离散化,这时我们需要用到函数cut: data <- rnorm(1000)
table(cut(data, breaks = quantile(data)))
library(Hmisc)
table(cut2(data, g = 4))
detach("package:Hmisc",
|
请发表评论