数据的清理

如同列夫托尔斯泰所说的那样:“幸福的家庭都是相似的,不幸的家庭各有各的不幸”,糟糕的恶心的数据各有各的糟糕之处,好的数据集都是相似的。一份好的,干净而整洁的数据至少包括以下几个要素:

1、每一个观测变量构成一列
2、每一个观测对象构成一行
3、每一个类型的观测单元构成一个表
就像我们最常接触的鸢尾花数据:

  1.  
    ## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
  2.  
    ## 1 5.1 3.5 1.4 0.2 setosa
  3.  
    ## 2 4.9 3.0 1.4 0.2 setosa
  4.  
    ## 3 4.7 3.2 1.3 0.2 setosa
  5.  
    ## 4 4.6 3.1 1.5 0.2 setosa
  6.  
    ## 5 5.0 3.6 1.4 0.2 setosa

每一列就是观测的指标:花瓣长度,花瓣宽度,萼片长度,萼片宽度,种类;每一行就是一株鸢尾花的观测值,构成整张表的元素就是四个数值变量,一个分类分类变量。

然而出于排版的考虑我们抓下来的数据往往不是那么的友好,比如说我们可以看到的数据通常是这样的:

  1.  
    ## religion <10k 10k-50k 50k-100k
  2.  
    ## 1 Agnostic 12 31 23
  3.  
    ## 2 Buddhist 58 43 43
  4.  
    ## 3 Catholic 79 56 23

而不是:

  1.  
    ## religion income freq
  2.  
    ## 1 Agnostic <10k 12
  3.  
    ## 2 Agnostic 10k-50k 58
  4.  
    ## 3 Agnostic 50k-100k 79
  5.  
    ## 4 Buddhist <10k 31

当然,除了这种把列表每一列代表一些数值这种情况外,还有多个变量储存为一列(比如列表不仅以"<10k","10k-50k","50k-100k"做表头,甚至还加上性别信息"m<10k","m10k-50k","m50k-100k","f<10k","f10k-50k","f50k-100k",其中m代表男性,f代表女性),还有更过分的将列表的变量不仅储存在列中,行中也有统计变量。

面对这些不好的table,我们首先要做的就是数据管理,将数据整理为一个干净的数据集。

数据管理

按照en:DAMA的定义:“数据资源管理,致力于发展处理企业数据生命周期的适当的建构、策略、实践和程序”。这是一个高层而包含广泛的定义,而并不一定直接涉及数据管理的具体操作(如关系数据库的技术层次上的管理)。我们这里主要讲述对于数据的变量命名与数据的合并,旨在方便数据共享。

数据管理首先要做的就是大致上了解你的数据,比如有什么样的变量,每一行大致长成什么样,最常用的就是head(),tail().
我们要做的基本上就是这么几项工作:

  • 给每一个变量命名,而不是V1,V2,如果有必要可以给出code book。

  • 每个变量名最好具有可读性,除非过长,否则不要用缩写,例如AgeAtDiagnosis这个命名远好于AgeDx。

  • 通常来说,最好将数据放在一张表里面,如果因为数据过多,项目过杂,分成了几张表。那么一定需要有一列使得这些表之间能够连接起来,但尽量避免这样做。

我们以UCI的Human Activity Recognition Using Smartphones Data Set 为例来看看数据是如何变成一个基本符合要求的数据。这个数据我们已经下载下来了,其中关于数据的详细信息可以参阅read me文档,由于UCI的数据通常都是一个基本合乎规范的数据集(主要是指它的数据集的变量名都是以V1,V2来命名的)加上一个code
book。那么我们看看各个数据的名称(在feature文件里)

  1.  

> setwd("C:/R/UCI HAR Dataset")> name<-read.table("./features.txt",stringsAsFactors = F)> head(name)  V1                V21  1 tBodyAcc-mean()-X2  2 tBodyAcc-mean()-Y3  3 tBodyAcc-mean()-Z4  4  tBodyAcc-std()-X5  5  tBodyAcc-std()-Y6  6  tBodyAcc-std()-Z

我们可以看到各个特征的名称直接标在数据上是非常不友善的,我们为了让他具有可读性,我们以展示在我们眼前的6个数据为例:

  1. variablename <- head(name)# 将标签中的大写字母转为小写,我们这里没有所以不再赋值,如果需要全变为大写,可以使用touppertolower(variablename$V2)
  1.  
    ## [1] "tbodyacc-mean()-x" "tbodyacc-mean()-y" "tbodyacc-mean()-z"
  2.  
    ## [4] "tbodyacc-std()-x" "tbodyacc-std()-y" "tbodyacc-std()-z"
  1. # 将变量名分离成3部分splitNames <- strsplit(variablename$V2, "-")splitNames[[1]]
  1. ## [1] "tBodyAcc" "mean()" "X"
  1. # 将变量名合成有意的名称named <- function(x) { rr <- paste(x[2], x[1], "-", x[3], sep = "")
  2. chartr("()", "of", rr)
  3. }
  4. sapply(splitNames, named)
  1.  
    ## [1] "meanoftBodyAcc-X" "meanoftBodyAcc-Y" "meanoftBodyAcc-Z"
  2.  
    ## [4] "stdoftBodyAcc-X" "stdoftBodyAcc-Y" "stdoftBodyAcc-Z"

用这样的名字给数据集命名就感觉舒服多了,我们将一些R中对字符串常用的操作函数总结如下,方便我们对数据名称的修改:

  • sub:替换字符串中的第一个模式为设定模式(pattern).

  • gsub:全局替换字符串中的相应模式

  • grep,grepl:这两个函数返回向量水平的匹配结果,grep仅返回匹配项的下标,而grepl返回所有的查询结果,并用逻辑向量表示有没有找到匹配。

  • nchar:统计字符串单字数目

  • substr:取子串

  • paste:将字符串链接起来,sep参数可以设置连接符

  • str_trim:去掉字符串空格

变量的名称建议满足如下要求:

  • 英文变量名尽可能用小写

  • 尽可能的描述清楚变量特征 (Diagnosis versus Dx)

  • 不要太复杂

  • 不要有下划线、点、空格

字符型变量应该满足:

  • 是因子类型的应该转化为factor

  • 因子尽可能具有一定的描述性 (例如:如果0/1表示真假,那么用TRUE/FALSE代替0/1;在表示性别时用Male/Female代替M/F)

接下来我们讨论数据集的合并,主要使用函数merge。
我们以下面两个数据集的合并为例:

  1. df1 <- data.frame(id = sample(1:10), reviewer_id = sample(5:14), time_left = sample(1321:1330),
  2. x = rnorm(10))df2 <- data.frame(id = sample(1:10), answer = rep("B", 10), time_left = sample(321:330),
  3. y = rnorm(10))
  4. head(df1, n = 3)
  1.  
    ## id reviewer_id time_left x
  2.  
    ## 1 3 9 1326 -0.9232
  3.  
    ## 2 10 5 1322 2.5069
  4.  
    ## 3 1 14 1330 2.2478
  1. head(df2, n = 3)
  1.  
    ## id answer time_left y
  2.  
    ## 1 1 B 329 0.8180
  3.  
    ## 2 10 B 327 1.4639
  4.  
    ## 3 9 B 323 0.8141

merge函数调用格式为:

  1.  
    merge(x, y, by = intersect(names(x), names(y)),
  2.  
    by.x = by, by.y = by, all = FALSE, all.x = all, all.y = all,
  3.  
    sort = TRUE, suffixes = c(".x",".y"),
  4.  
    incomparables = NULL, ...)

参数说明:

  • x,y:两个数据框

  • by, by.x, by.y:指定用于合并的列的名称。

  • all,all.x,all.y:默认的all = FALSE相当于自然连接, 或者说是内部链接. all.x = TRUE是一个左连接, all.y = TRUE是一个又连接, all = TRUE 相当于一个外部链接.

仔细观察下面3个例子你就会发现其中的奥秘:

  1. mergedData <- merge(df1,df2,by.x="reviewer_id",by.y="id",all=TRUE)
  2. head(mergedData)
  1.  
    ## reviewer_id id time_left.x x answer time_left.y y
  2.  
    ## 1 1 NA NA NA B 329 0.8180
  3.  
    ## 2 2 NA NA NA B 330 -0.7706
  4.  
    ## 3 3 NA NA NA B 325 -0.4851
  1. mergedData <- merge(df1,df2,by.x="id",by.y="id",all=TRUE)
  2. head(mergedData)
  1.  
    ## id reviewer_id time_left.x x answer time_left.y y
  2.  
    ## 1 1 14 1330 2.24783 B 329 0.8180
  3.  
    ## 2 2 12 1324 1.03181 B 330 -0.7706
  4.  
    ## 3 3 9 1326 -0.92317 B 325 -0.4851
  5.  
    ## 4 4 7 1321 -0.07841 B 322 0.1801
  1. mergedData2 <- merge(df1,df2,all=TRUE)
  2. head(mergedData2)
  1.  
    ## id time_left reviewer_id x answer y
  2.  
    ## 1 1 329 NA NA B 0.8180
  3.  
    ## 2 1 1330 14 2.2478 <NA> NA
  4.  
    ## 3 2 330 NA NA B -0.7706

在plyr包中还提供了join,join_all,arrange等函数来实现表的连接,但我想merge这个函数已经足够用了,所以我们不在多说。当然,在极少数特别好的情况下(比如列的变量是一致的,或者行的观测个体是一致的时候)rbind,cbind也是有用的。

有些时候我们会遇到一些特殊的字符串:日期。R中提供了各式各样的函数来处理时间:

  1. Sys.setlocale("LC_TIME", "C")
  1. ## [1] "C"
  1. x <- c("1jan1960", "2jan1960", "31mar1960", "30jul1960")z <- as.Date(x, "%d%b%Y")
  2. format(z, "%a %b %d")
  1. ## [1] "Fri Jan 01" "Sat Jan 02" "Thu Mar 31" "Sat Jul 30"
  1. weekdays(z)
  1. ## [1] "Friday" "Saturday" "Thursday" "Saturday"
  1. julian(z)
  1.  
    ## [1] -3653 -3652 -3563 -3442
  2.  
    ## attr(,"origin")
  3.  
    ## [1] "1970-01-01"
  1. transform(z, weekend = as.POSIXlt(z, format = "%Y/%m/%d")$wday %in% c(0, 6))
  1.  
    ## X_data weekend
  2.  
    ## 1 1960-01-01 FALSE
  3.  
    ## 2 1960-01-02 TRUE
  4.  
    ## 3 1960-03-31 FALSE
  5.  
    ## 4 1960-07-30 TRUE

数据操作与整合

说到数据操作,这也是一个十分宽泛的话题,在这里我们就以下4个方面进行介绍:

  • 数据的筛选,过滤:根据一些特定条件选出或者删除一些观测

  • 数据的变换:增加或者修改变量

  • 数据的汇总:分组计算数据的和或者均值

  • 数据的排序:改变观测的排列顺序

然而在进行这一切之前首先要做的就是了解你的数据,我们以世界银行的数据Millennium Development Goals为例,来一步步演示如何进行数据操作:

  1. if (!file.exists("C:/Users/yujun/Documents/MDG_Data.csv")) {
  2. download.file("http://databank.worldbank.org/data/download/MDG_csv.zip","F:/MDG.zip")
  3. unzip("F:/MDG.zip")
  4. }MDstats<-read.csv("C:/Users/yujun/Documents/MDG_Data.csv")

首先先来看一部分数据:

  1. head(MDstats)
  1.  
    ## Country.Name Country.Code
  2.  
    ## 1 Afghanistan AFG
  3.  
    ## 2 Afghanistan AFG
  4.  
    ## 3 Afghanistan AFG
  1. tail(MDstats)
  1.  
    ## Country.Name Country.Code
  2.  
    ## 33093 Zimbabwe ZWE
  3.  
    ## 33094 Zimbabwe ZWE
  4.  
    ## 33095 Zimbabwe ZWE
  5.  
    ## 33096 Zimbabwe ZWE

我们显然发现了这不是一个tidy data,那么我们先将其变换为我们喜欢的tidy data,之后再看看数据摘要及数据集各单元的属性:

  1.  
    ## countryname countrycode
  2.  
    ## 1 Afghanistan AFG
  3.  
    ## 2 Afghanistan AFG
  4.  
    ## 3 Afghanistan AFG
  5.  
    ## 4 Afghanistan AFG
  6.  
    ## 5 Afghanistan AFG
  7.  
    ## 6 Afghanistan AFG
  8.  
    ## indicatorname
  9.  
    ## 1 Adolescent fertility rate (births per 1,000 women ages 15-19)
  10.  
    ## 2 Agricultural support estimate (% of GDP)

我们可以看看各个数值数据的分位数:

  1. quantile(MDstatsMelt$value,na.rm=TRUE)
  1.  
    ## 0% 25% 50% 75% 100%
  2.  
    ## -9.431e+08 1.054e+01 5.060e+01 9.843e+01 7.526e+13

看看各个国家的统计数据有多少:

  1. table(MDstatsMelt$countrycode)
  1.  
    ##
  2.  
    ## ABW ADO AFG AGO ALB ARB ARE ARG ARM ASM ATG AUS AUT AZE BDI
  3.  
    ## 3216 3216 3216 3216 3216 3216 3216 3216 3216 3216 3216 3216 3216 3216 3216
  4.  
    ## BEL BEN BFA BGD BGR BHR BHS BIH BLR BLZ BMU BOL BRA BRB BRN

看看缺失值:

  1. sum(is.na(MDstatsMelt$value)) #总的缺失值
  1. ## [1] 495519
  1. colSums(is.na(MDstatsMelt)) #每一列的缺失值
  1.  
    ## countryname countrycode indicatorname indicatorcode year
  2.  
    ## 0 0 0 0 0
  3.  
    ## value
  4.  
    ## 495519
  1. # 如果我们用回tidy前的数据集,那么这个函数会显得比较有用colSums(is.na(MDstats))
  1.  
    ## Country.Name Country.Code Indicator.Name Indicator.Code X1990
  2.  
    ## 0 0 0 0 23059
  3.  
    ## X1991 X1992 X1993 X1994 X1995
  4.  
    ## 22293 21672 21753 21491 20970
  5.  
    ## X1996 X1997 X1998 X1999 X2000
  6.  
    ## 20680 20448 20419 19933 18822
  1. # 等价的处理方式stat <- function(x) {
  2. sum(is.na(x))
  3. }
  4. tapply(MDstatsMelt$value, MDstatsMelt$year, stat)
  1.  
    ## X1990 X1991 X1992 X1993 X1994 X1995 X1996 X1997 X1998 X1999 X2000 X2001
  2.  
    ## 23059 22293 21672 21753 21491 20970 20680 20448 20419 19933 18822 19598
  3.  
    ## X2002 X2003 X2004 X2005 X2006 X2007 X2008 X2009 X2010 X2011 X2012 X2013
  4.  
    ## 19119 19478 19269 18704 19044 18641 19256 19162 18756 20360 21967 30625

统计某个国家的统计数据占总统计数目的多少

  1. table(MDstatsMelt$countryname %in% c("China"))
  1.  
    ##
  2.  
    ## FALSE TRUE
  3.  
    ## 791136 3216
  1. prop <- table(MDstatsMelt$countryname %in% c("China"))[2]/sum(table(MDstatsMelt$countryname %in% c("China")))prop
  1.  
    ## TRUE
  2.  
    ## 0.004049

看看数据集的大小:

  1. object.size(MDstatsMelt)
  1. ## 22301832 bytes
  1. print(object.size(MDstatsMelt),units="Mb")
  1. ## 21.3 Mb

至此,我们可以说我们对数据有了一定的了解。另外值得一提的是,对于某些特定的数据,也许xtabs,ftable是有用的。

数据的筛选

要提取相应内容的数据,最为常用的就是提取相应元素,比如提取某个元素,提取某一行,某一列。我们通过下面下面的例子来学习:

  1. data<-data.frame(a=sample(1:10),b=rep(c("a","b"),each=5),cdf=rnorm(10))data
  1.  
    ## a b cdf
  2.  
    ## 1 1 a 0.5755
  3.  
    ## 2 10 a 0.8087
  4.  
    ## 3 2 a 0.9810
  5.  
    ## 4 7 a -0.4635
  6.  
    ## 5 4 a 0.5094
  1. #提取相应元素data[2,1]
  1. ## [1] 10
  1. data[[1]][[2]]
  1. ## [1] 10
  1. data[[c(1,2)]]
  1. ## [1] 10
  1. data$a[2]
  1. ## [1] 10
  1. #提取某一列data[[3]]
  1.  
    ## [1] 0.5755 0.8087 0.9810 -0.4635 0.5094 1.0514 -1.5338 1.0047
  2.  
    ## [9] 1.0004 -1.3566
  1. data$cdf
  1.  
    ## [1] 0.5755 0.8087 0.9810 -0.4635 0.5094 1.0514 -1.5338 1.0047
  2.  
    ## [9] 1.0004 -1.3566
  1. data$c
  1.  
    ## [1] 0.5755 0.8087 0.9810 -0.4635 0.5094 1.0514 -1.5338 1.0047
  2.  
    ## [9] 1.0004 -1.3566
  1. data[["c"]]
  1. ## NULL
  1. data[["c", exact = FALSE]]
  1.  
    ## [1] 0.5755 0.8087 0.9810 -0.4635 0.5094 1.0514 -1.5338 1.0047
  2.  
    ## [9] 1.0004 -1.3566

数据的筛选还有一个最为常用的的就是移除缺失值:

  1. 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
  1.  
    ## a b cdf
  2.  
    ## 1 5 a -0.276400
  3.  
    ## 2 1 a -1.861240
  1. good <- complete.cases(data)data[good, ]
  1.  
    ## a b cdf
  2.  
    ## 1 5 a -0.2764
  3.  
    ## 2 1 a -1.8612
  4.  
    ## 3 3 a -2.0280
  1. bad <- as.data.frame(is.na(data))data[!(bad$a|bad$b|bad$c),]
  1.  
    ## a b cdf
  2.  
    ## 1 5 a -0.2764
  3.  
    ## 2 1 a -1.8612

数据筛选有时是为了获得符合条件的数据:

  1. 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
  1.  
    ## var1 var2 var3
  2.  
    ## 2 5 NA 13
  3.  
    ## 5 3 6 15
  4.  
    ## 1 2 NA 12
  5.  
    ## 3 1 8 11
  6.  
    ## 4 4 9 14
  1. X[(X$var1 <= 3 & X$var3 > 11),]
  1.  
    ## var1 var2 var3
  2.  
    ## 5 3 6 15
  3.  
    ## 1 2 NA 12
  1. subset(X,(X$var1 <= 3 & X$var3 > 11))
  1.  
    ## var1 var2 var3
  2.  
    ## 5 3 6 15
  3.  
    ## 1 2 NA 12
  1. X[(X$var1 <= 3 | X$var3 > 15),]
  1.  
    ## var1 var2 var3
  2.  
    ## 5 3 6 15
  3.  
    ## 1 2 NA 12
  4.  
    ## 3 1 8 11
  1. X[which(X$var1 <= 3 | X$var3 > 15),]
  1.  
    ## var1 var2 var3
  2.  
    ## 5 3 6 15
  3.  
    ## 1 2 NA 12
  4.  
    ## 3 1 8 11

对于取子集的函数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."

数据的变换

常见的数据变换函数有:

  • abs(x) 绝对值

  • sqrt(x) 开根号

  • ceiling(x) 求上线,例:ceiling(3.475) = 4

  • floor(x) 求下线,例:floor(3.475) = 3

  • round(x,digits=n) 四舍五入,例:round(3.475,digits=2) = 3.48

  • signif(x,digits=n) 四舍五入,例:signif(3.475,digits=2) = 3.5

  • cos(x), sin(x) etc.三角变换

  • log(x) 对数变换

  • log2(x), log10(x) 以2、10为底的对数变换

  • exp(x) 指数变换

除此以外,我们还经常对数据加标签,以期在回归中测量其效应。我们以MASS包的shuttle数据集为例,想知道不同类型的风(wind)是否需要使用不同的装载机(use),这里我们希望将head wind标记为1,auto use也记为1,我们可以按照如下办法设置虚拟变量:

  1. library(MASS)
  2. data(shuttle)
  3. head(shuttle)
  1.  
    ## stability error sign wind magn vis use
  2.  
    ## 1 xstab LX pp head Light no auto
  3.  
    ## 2 xstab LX pp head Medium no auto
  4.  
    ## 3 xstab LX pp head Strong no auto
  5.  
    ## 4 xstab LX pp tail Light no auto
  6.  
    ## 5 xstab LX pp tail Medium no auto
  7.  
    ## 6 xstab LX pp tail Strong no auto
  1. ## Make our own variables just for illustrationshuttle$auto <- 1 * (shuttle$use == "auto")shuttle$headwind <- 1 * (shuttle$wind == "head")
  2. head(shuttle)
  1.  
    ## stability error sign wind magn vis use auto headwind
  2.  
    ## 1 xstab LX pp head Light no auto 1 1
  3.  
    ## 2 xstab LX pp head Medium no auto 1 1

当然对于因子类型变量,relevel函数在线性模型的分析中也是能取得等价效果的。

有些时候,我们还常常将连续数据离散化,这时我们需要用到函数cut:

  1. data <- rnorm(1000)
  2. table(cut(data, breaks = quantile(data)))
  1.  
    ##
  2.  
    ## (-3.28,-0.637] (-0.637,0.0321] (0.0321,0.672] (0.672,3.37]
  3.  
    ## 249 250 250 250
  1. library(Hmisc)
  2. table(cut2(data, g = 4))
  1.  
    ##
  2.  
    ## [-3.2847,-0.6372) [-0.6372, 0.0334) [ 0.0334, 0.6829) [ 0.6829, 3.3704]
  3.  
    ## 250 250 250 250
  1. detach("package:Hmisc", unload = TRUE)

获得分组区间后,我们只需要将区间的因子重命名就成功的实现了数据的离散化。

数据的汇总

对数据进行汇总,分类汇总是我们也比较常用的,比如对行或列求和,求均值,求分位数:

  1. data <- matrix(1:16, 4, 4)data
  1.  
    ## [,1] [,2] [,3] [,4]
  2.  
    ## [1,] 1 5 9 13
  3.  
    ## [2,] 2 6 10 14
  4.  
    ## [3,] 3 7 11 15
  5.  
    ## [4,] 4 8 12 16
  1. apply(data, 2, mean)
  1. ## [1] 2.5 6.5 10.5 14.5
  1. apply(data, 1, sum)
  1. ## [1] 28 32 36 40
  1. apply(data, 1, quantile, probs = c(0.25, 0.75))
  1.  
    ## [,1] [,2] [,3] [,4]
  2.  
    ## 25% 4 5 6 7
  3.  
    ## 75% 10 11 12 13
  1. apply(data, 2, quantile, probs = c(0.25, 0.75))
  1.  
    ## [,1] [,2] [,3] [,4]
  2.  
    ## 25% 1.75 5.75 9.75 13.75
  3.  
    ## 75% 3.25 7.25 11.25 15.25

有时候,为了更快些,我们会用一些函数替代apply:

  • rowSums = apply(x, 1, sum)

  • rowMeans = apply(x, 1, mean)

  • colSums = apply(x, 2, sum)

  • colMeans = apply(x, 2, mean)

我们有时也会处理一些列表,对列表的分类汇总我们会用到sapply,lapply,不同的是前者返回一个向量或矩阵,后者返回一个列表,例:

  1. x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE))
  2. lapply(x, mean)
  1.  
    ## $a
  2.  
    ## [1] 5.5
  3.  
    ##
  4.  
    ## $beta
  5.  
    ## [1] 4.535
  6.  
    ##
  7.  
    ## $logic
  8.  
    ## [1] 0.5
  1. sapply(x, mean)
  1.  
    ## a beta logic
  2.  
    ## 5.500 4.535 0.500
  1. # median and quartiles for each list elementlapply(x, quantile, probs = 1:3/4)
  1.  
    ## $a
  2.  
    ## 25% 50% 75%
  3.  
    ## 3.25 5.50 7.75
  4.  
    ##
  5.  
    ## $beta
  6.  
    ## 25% 50% 75%
  7.  
    ## 0.2516 1.0000 5.0537
  8.  
    ##
  9.  
    ## $logic
  10.  
    ## 25% 50% 75%
  11.  
    ## 0.0 0.5 1.0
  1. sapply(x, quantile)
  1.  
    ## a beta logic
  2.  
    ## 0% 1.00 0.04979 0.0
  3.  
    ## 25% 3.25 0.25161 0.0
  4.  
    ## 50% 5.50 1.00000 0.5
  5.  
    ## 75% 7.75 5.05367 1.0
  6.  
    ## 100% 10.00 20.08554 1.0

有时候我们还会进行分类汇总,如统计男女工资均值,这时你可以用tapply:

  1. group <- (rbinom(32, n = 20, prob = 0.4))groups <- factor(rep(1:2,10))
  2. tapply(group, groups, length)
  1.  
    ## 1 2
  2.  
    ## 10 10
  1. tapply(group, groups, sum)
  1.  
    ## 1 2
  2.  
    ## 135 122
  1. tapply(group, groups, mean)
  1.  
    ## 1 2
  2.  
    ## 13.5 12.2

数据的排序

数据的排序需要用到的函数常见的有sort和order,其中sort返回排序的结果,order返回对应数据的排名。例:

  1. 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)] <- NAsort(X$var2,decreasing=TRUE)
  1. ## [1] 9 8 6
  1. sort(X$var2,decreasing=TRUE,na.last=TRUE)
  1. ## [1] 9 8 6 NA NA
  1. order(X$var2,decreasing=TRUE)
  1. ## [1] 2 5 4 1 3
  1. order(X$var2,decreasing=TRUE,na.last=TRUE)
  1. ## [1] 2 5 4 1 3
  1. X[order(X$var2),]
  1.  
    ## var1 var2 var3
  2.  
    ## 2 1 6 13
  3.  
    ## 5 5 8 15
  4.  
    ## 4 4 9 11
  5.  
    ## 1 2 NA 14
  6.  
    ## 3 3 NA 12
  1. #deal with the linkX$var2[c(1)] <- sample(na.omit(X$var2),1)X[order(X$var2,X$var3),]
  1.  
    ## var1 var2 var3
  2.  
    ## 2 1 6 13
  3.  
    ## 5 5 8 15
  4.  
    ## 4 4 9 11
  5.  
    ## 1 2 9 14
  6.  
    ## 3 3 NA 12

有些时候,更为强大的aggregate函数是我们需要的,我们以R的内置数据集state.x77为例:

  1. aggregate(state.x77, list(Region = state.region, Cold = state.x77[,"Frost"] > 130), mean)
  1.  
    ## Region Cold Population Income Illiteracy Life Exp Murder HS Grad
  2.  
    ## 1 Northeast FALSE 8802.8 4780 1.1800 71.13 5.580 52.06
  3.  
    ## 2 South FALSE 4208.1 4012 1.7375 69.71 10.581 44.34
  4.  
    ## 3 North Central FALSE 7233.8 4633 0.7833 70.96 8.283 53.37
  5.  
    ## 4 West FALSE 4582.6 4550 1.2571 71.70 6.829 60.11
  6.  
    ## 5 Northeast TRUE 1360.5 4308 0.7750 71.44 3.650 56.35
  7.  
    ## 6 North Central TRUE 2372.2 4589 0.6167 72.58 2.267 55.67

当然,这里还有一个更为基本与灵活的函数,split,可以帮助你将数据分为若干张满足分类条件的表,你可以一张一张的处理它们:

  1. library(datasets)
  2. head(airquality)
  1.  
    ## Ozone Solar.R Wind Temp Month Day
  2.  
    ## 1 41 190 7.4 67 5 1
  3.  
    ## 2 36 118 8.0 72 5 2
  4.  
    ## 3 12 149 12.6 74 5 3
  5.  
    ## 4 18 313 11.5 62 5 4
  6.  

用R语言做数据清理的更多相关文章

  1. 用R语言做数据清理(详细教程)

    数据的清理 如同列夫托尔斯泰所说的那样:“幸福的家庭都是相似的,不幸的家庭各有各的不幸”,糟糕的恶心的数据各有各的糟糕之处,好的数据集都是相似的.一份好的,干净而整洁的数据至少包括以下几个要素: 1. ...

  2. 用R语言提取数据框中日期对应年份(列表转矩阵)

    用R语言提取数据框中日期对应年份(列表转矩阵) 在数据处理中常会遇到要对数据框中的时间做聚类处理,如从"%m/%d/%Y"中提取年份. 对应操作为:拆分成列表——列表转矩阵——利用 ...

  3. R语言读写数据

    R语言读写数据 一般做模型的时候,从外部的excel中读入数据,我现在常用的比较多的是read_csv(file) 读入之前先把excel数据转化成.csv格式 同样的把结果输出来的时候用的是writ ...

  4. R语言进行数据预处理wranging

    R语言进行数据预处理wranging li_volleyball 2016年3月22日 data wrangling with R packages:tidyr dplyr Ground rules ...

  5. 用R语言 做回归分析

    使用R做回归分析整体上是比较常规的一类数据分析内容,下面我们具体的了解用R语言做回归分析的过程. 首先,我们先构造一个分析的数据集 x<-data.frame(y=c(102,115,124,1 ...

  6. R语言进行数据预处理

    R语言进行数据预处理wranging li_volleyball 2016年3月22日 data wrangling with Rpackages:tidyr dplyr Ground rules l ...

  7. R语言 我要如何开始R语言_数据分析师

    R语言 我要如何开始R语言_数据分析师 我要如何开始R语言? 很多时候,我们的老板跟我们说,这个东西你用R语言去算吧,Oh,My god!什么是R语言?我要怎么开始呢? 其实回答这个问题很简单,首先, ...

  8. [译]用R语言做挖掘数据《七》

    时间序列与数据挖掘 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou,密码shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用 ...

  9. [译]用R语言做挖掘数据《六》

    异常值检测 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou,密码shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境,实验中会用到程序: ...

随机推荐

  1. Django系统

    #Django系统 -环境 - python3.6 - django1.8 -参考资料 - [django中文教程](http://python.usyiyi.cn) - django架站的16堂课 ...

  2. Go语言 切片长度和容量

    package main import "fmt" func main() { s := []int{2, 3, 5, 7, 11, 13} printSlice(s) // Sl ...

  3. 真正可用的安卓webview html图片上传限制突破处理(拍照+相册都可以用)

    两篇起步使用webview参考文章,第一篇解除限制,但会调用外部浏览器打开链接,第二篇 覆盖shouldOverrideUrlLoading return true https://www.jb51. ...

  4. Oracle程序备份

    --使用root用户备份 su - root mkdir -p /oracle/data_dump/backup_soft nohup tar -cvf /oracle/data_dump/backu ...

  5. 解决git冲突造成的Please move or remove them before you can merge

    git clean -d -fx “” 其中x —–删除忽略文件已经对git来说不识别的文件d —–删除未被添加到git的路径中的文件f —–强制运行如果你确定这货已经没用了,并且git status ...

  6. 820板子安装python

    1. 需要安装python, 从 python.org上下载版本,我下的是python3.5,网上搜索到的是python2.7的交叉编译过程 和820的结合下. 需要注意,先把820的环境设置好,就是 ...

  7. python的高级数组之稀疏矩阵

    稀疏矩阵的定义: 具有少量非零项的矩阵(在矩阵中,若数值0的元素数目远多于非0元素的数目,并且非0元素分布没有规律时,)则称该矩阵为稀疏矩阵:相反,为稠密矩阵.非零元素的总数比上矩阵所有元素的总数为矩 ...

  8. net Core TOptions和热更新

    TOptions接口 net Core 项目有个appsettings.json文件,程序默认也是读取的这个文件,appsettings.json是一个配置文件 我们可以把appsettings.js ...

  9. 全志A33驱动GT911触摸屏

    0x00 环境说明: 所使用的开发板为锐尔威视的插针版A33_Vstar 触摸屏驱动IC为GT911 接线参照开发板的TP线路 0x01 修改系统配置文件: 笔者所使用的A33开发板的系统配置文件路径 ...

  10. FG面经Prepare: BST to Double LinkedList

    BST to double linkedlist in inorder traversal sequenceFollow Up: 如果这个BST自带prev, next, 给一个value,插进去这个 ...