相关文章推荐

R语言中很多字符函数都能识别正则表达式,而最重要的函数就是gregexpr()。

gregexpr
function (pattern, text, ignore.case = FALSE, perl = FALSE, fixed = FALSE, 
    useBytes = FALSE) 
    if (!is.character(text)) 
        text <- as.character(text)
    .Internal(gregexpr(as.character(pattern), text, ignore.case, 
        perl, fixed, useBytes))
<bytecode: 0x09331de4>
<environment: namespace:base>

该函数的第一个参数是正则表达式,前后需要用引号,对元字符进行转义时要用\。 第二个参数是等待处理的文本。 那么用如下三行代码,我们从word字符向量中得到一个列表, 其中第一项元素中的5表示电邮地址从第5个字符位置开始,24表示电邮地址长度为24。

word <- c('abc [email protected]','text with no email','first [email protected] also [email protected]')
pattern <- '[-A-Za-z0-9_.%]+@[-A-Za-z0-9_.%]+\\.[A-Za-z]+'
(gregout <- gregexpr(pattern,word))
# output
[[1]]
[1] 5
attr(,"match.length")
[1] 24
attr(,"useBytes")
[1] TRUE
[[2]]
[1] -1
attr(,"match.length")
[1] -1
attr(,"useBytes")
[1] TRUE
[[3]]
[1]  7 27
attr(,"match.length")
[1] 14 17
attr(,"useBytes")
[1] TRUE

下一步我们需要将电邮地址抽取出来,此时配合substr函数,即可根据需要字符串的位置来提取子集。

substr(word[1],gregout[[1]],gregout[[1]]+attr(gregout[[1]],'match.length')-1)
# 函数getcontent,参数s表示待处理的文本,参数g表示的是通过gregexpr函数处理后的结果。
# 这个函数我们在后面还会用到。
getcontent <- function(s,g) {
    substring(s,g,g+attr(g,'match.length')-1)
getcontent(word[1],gregout[[1]])

实际的数据抓取工作中,如何使用正则表达式。 任务目标是要抓取豆瓣电影中250部最佳电影的资料。 R代码如下:

url <-'http://movie.douban.com/top250?format=text'
# 获取网页原代码,以行的形式存放在web变量中
web <- readLines(url,encoding="UTF-8")
# 找到包含电影名称的行编号
name <- web[grep('<td headers="m_name">',web)+1]
# 用正则表达式来提取电影名
gregout <- gregexpr('>\\w+',name)
movie.names = 0
for (i in 1:250) {
    movie.names[i] <-getcontent(name[i],gregout[[i]])
movie.names <- sub('>','',movie.names)
# 找到包含电影发行年份的行编号并进行提取
year <- web[grep('<span class="year">',web)] 
movie.year <- substr(year,36,39)
# 找到包含电影评分的行编号并进行提取
score <- web[grep('<td headers="m_rating_score">',web)+1]
movie.score <- substr(score,21,23)
# 找到包含电影评价数量的行编号并进行提取
rating <- web[grep('<td headers="m_rating_num">',web)+1]
movie.rating <- sub(' *','',rating)
# 合成为数据框
movie <- data.frame(names=movie.names,year=as.numeric(movie.year),
                    score=as.numeric(movie.score),rate=as.numeric(movie.rating))
# 绘散点图
library(ggplot2)
p <- ggplot(data=movie,aes(x=year,y=score))
p+geom_point(aes(size=rate),colour='lightskyblue4',
             position="jitter",alpha=0.8)+
  geom_point(aes(x=1997,y=8.9),colour='red',size=4)
  
  • 一个是大神Hadley的一系列数据处理包,主要有reshape2 dplyr tidyr 包
  • (虽然Hadley最出名的不是这些,而是ggplot2绘图包,但是这些包在数据分析上也都是首屈一指的)。
  • 另一个是data.table包.
  • # load R package
    library(dplyr)
    # Create Data.frame, also can use as.data.frame(matrix) and read.csv()
    name1 <- c("Bob","Mary","Jane","Kim")
    name2 <- c("Bob","Mary","Kim","Jane")
    weight <- c(60,65,45,55)
    height <- c(170,165,140,135)
    birth <- c("1990-1","1980-2","1995-5","1996-4")
    accept <- c("no","ok","ok","no")
    df1 <- data.frame(name1,weight,height)
    rownames(df1) <- letters[1:4] # 赋予行名
    df2 <- data.frame(name2,birth,accept)
    

    extract Data–Position,rowname/columnname,logic value

    # 通过[]选择坐标,确定点1 position
    df1[2,3]
    # 使用向量确定多个点multi position
    df1[c(2,4),c(1,3)]
    # 通过[]选择行列名rowname/columnname
    df1["a","weight"]
    df1["a",2] # 混搭
    # 通过矩阵提取多个点,一列指定行,一列指定列
    df1[cbind(c(1,2,1),3:1)]
    df1[cbind(c("a","b"), c("weight","height"))]
    # 通过[]少选择一个维度,整行整列地选择(这是比选择行多的一种方法)
    df1[2,] # 取行
    df1[,3] # 取列
    df1[c(2,3),] # 取多行
    df1[,c(2,3)] # 取多列
    df1["a",]
    df1[,"weight"]
    df1[3] # 只接一个数字,选择列
    df1[c(2,3)] # 使用向量则选择多列
    df1$weight # 通过$选择列名名字来选择列
    # 列名放在[]中选取列
    df1["weight"]
    df1[c("weight","height")] # 使用向量选择多列
    select(df2,accept)  # dplyr包中函数,等价于 df2$accept
    

    在选择行和列上有必要进一步说明,关于取出来的仍是数据框还是向量的问题

    这是提取数据是否同时进行降维的问题。 即使是只有一列的数据框,它仍是二维的,只有变成向量才算是一维的。 上面涉及到的多种提取行列的方法,默认得到的结果是数据框还是向量是不一样的. 但是二者之间是有办法相互转化的。

    # 取行和取列默认不一样
    class(df1[,3]) # "numeric" numeric代表这样提取得到的是一个向量
    class(df1[2,]) # "data.frame"data.frame代表这样提取得到的仍是一个数据框
    # 另外三种
    class(df1[3]) # "data.frame"
    class(df1["weight"]) # "data.frame"
    class(df1$weight) # "numeric"
    

    对于取两个坐标[]的方法来说,drop参数可以调整输出结果

    # drop=T是降维的意思
    class(df1[,3,drop=F]) # "data.frame"
    class(df1[2,,drop=T]) # "list"
    # 取行用drop也不能转化为向量,那就用unlist
    class(unlist(df1[2,])) # "numeric"
    

    对于只接受一个维度参数的方法来说[[]]相当于$,可以实现降维

    class(df1[["weight"]]) # "numeric"
    class(df1[[2]]) # "numeric"
    # 注意:[[]]不能作用到选取多列的情况上,因为多列谈不上降维
    df1[[c("weight","height")]] # 报错
    df1[[1:3]] # 报错
    

    1.关于[[]]和$等关于降维方面的使用,读者可以自行在list和matrix上试。 使用下面一条命令查看帮助文档

    help(`[`) # R语言一切都是函数
    

    2.模糊匹配

    df1$wei # 前面匹配就可以选出那一列
    # 但是必须是唯一匹配
    df1$weig <- 1:4 # 新增加一列weig
    df1$wei # 匹配出两个都满足(weigth和weig),则返回NULL
    # 是否支持模糊匹配也可以用参数exact调整
    df1[["hei"]] # 默认不支持模糊匹配
    df1[["hei",exact=F]] # 支持
    df1["hei"]; df1["hei",exact=F] # 单个[]加了也不支持
    # 模糊匹配在函数参数使用上也有体现
    seq(1,10,length.out=10)
    seq(1,10,len=10)
    

    3.如果指定的数字不是整数,会自动向下取整

    (i <- 3.999999999) # 返回4,因为当前保留的位数不够
    # 如果想要改变保留位数,可以用options(digits = 10)修改
    # 不过内存中存储的还是3.999999999
    (1:5)[i]  # 3
    

    通过逻辑值判断选取

    # 通过判断语句
    df2[df2$accept=="no"|name2=="Bob",]
    subset(df2,accept=="no") # R自带提取函数
    filter(df2,accept=="no"|name2=="Bob") # dplyr包提取函数
    

    上面这种通过判断来选取的方式,有一个背后的原理. 我们拿[]来说,这是通过逻辑值向量进行的选取

    df2$accept=="no"|name2=="Bob"
    # TRUE FALSE FALSE  TRUE
    # 先生成等长的逻辑向量,放在行的位置
    # 列不写代表所有列都要
    # 而只有对应TRUE的行才会被提取出来
    df2[df2$accept=="no"|name2=="Bob",]
    # 相当于
    df2[c(T,F,F,T),]
    

    知道了这个原理之后,我们就可以更加灵活地提取数据. 因为[]中放置的不一定必须是本数据框中的变量, 只要是等长逻辑值向量就可以了(注意最后的逗号不要忘记写就好)

    df2[df1$weight>50,]
    

    提取衍生物

    我们使用过程中可能涉及到的,修改数据框,按照行或列进行排序,删除某行某列,插入某行某列。 这些如果都单独来学,会感觉命令非常多、非常乱. 但如果看成是提取的衍生物,则不需要花多少精力就能掌握。 因为这些其实都是使用了提取的方法,只是各自加入了自己的原理,就包装成了另外一种东西。 我们一项一项来看:

    这里修改数据框其实只是把需要修改的地方用提取的方法提取出来,再赋个值. 就实现了对原数据框的更改,基本上没有什么新东西。

    df1[2,3] <- 160;df1
    df2$accept[df2$accept=="ok"] <- "yes"
    df2 # 数据框发生了改变
    

    我们会发现,这里每次使用数据框中的一列时,都要使用$,非常麻烦,可以使用within函数避免这样的麻烦

    df2 <- data.frame(name2,birth,accept,stringsAsFactors=F)
    within(df2,{accept[accept=="ok"] <- "yes"
          name2[name2=="Bob"]<-"BOB"})
    

    当其他时候使用数据框中的列进行计算时,如果不想用$,可以使用attach函数

    df2 <- data.frame(name2,birth,accept,stringsAsFactors=F)
    attach(df2)
    2*weight
    detach(df2)
    

    用这种方法一定要注意最后detach,否则会搞乱命名空间,由于容易忘记,一般不推荐这种方法,我们还可以使用with函数

    with(df2,{a <- weight*2
              a^3})
    

    不想要哪行,就在哪行用负数,其实相当于提取了其他行,组成了一个新的数据框。 根据这个原理,使用逻辑值向量也可以实现删除行列。

    df1[-c(2,3),]
    df1[,c(T,F,T)]
    

    R语言使用基础函数处理向量、数据框等,都不能直接对其本身修改. 无论是改变一个值,还是排序,删除某一列,得到的都不再是原来的数据框了。 所以排序其实就是一个按顺序提取的过程。

    R中自带的方法是使用order函数,生成大小顺序的索引

    df1_order_row <- df1[order(df1$weight),]
    # 我们可以拆分来看
    order(df1$weight) # 3 4 1 2
    # 上面的结果意味着第三个是最小的,最先被提取出来,放在第一行,接下来是第4个第二小……
    # 先按体重,再按身高排序(当体重一样时)
    df1_order_row <- df1[order(df1$weight,df1$height),]
    # 按照列名对列排序也是一样
    df1_order_col <- df1[,order(colnames(df1))]
    # 使用dplyr包对行更方便、高效地处理
    arrange(df1,weight,height)
    

    由于上面说到的特性,R语言没有办法在原有向量或数据框中插入内容. 唯一的方法就是按照要插入的位置,将数据框分开,即提取出dfa和dfb,再用二者和要加入的内容拼接。 这种方法非常繁琐,尤其是当要在很多地方插入的情况下. 本人目前没有找到更好的方法,如果读者有好的方法可以在评论区留言。

    管道操作–基于 magrittr 包,里面有如下几个函数

    最常用的是第一个 %>% ,如果你载入Hadley的包,就自动可以使用这个函数,不用另外加载magrittr包. 如果想了解其他函数再载入这个包,查看文档来学习,或者看r-magrittr

    管道操作除了这个包,还有 pipeR 包,这是另外一个系统,有兴趣的可以去学一下. 这里简要介绍一下 %>% 函数

    library(dplyr)
    name2 <- c("Bob","Mary","Kim","Jane")
    weight <- c(60,65,45,55)
    height <- c(170,165,140,135)
    accept <- c("no","ok","ok","no")
    df <- data.frame(name2,weight,height,accept)
    # 下面两个操作等价
    select(df,weight:accept)
    df %>% select(weight:accept)
    # 所以 %>% 的作用在于把前面的内容放到后面函数中,作为第一个参数。
    # 使用这个符号的好处有
    # 1. 使代码更加易读
    # 2. 减少中间变量
    
    # 01, 通过管道函数从前往后读
    # 拿到数据集df,先提取首字母是w的列select(starts_with("w")),
    # 乘2`*`(2),转化为向量unlist(),
    # 使用这个向量创建一个2行的矩阵matrix(nrow=2),对矩阵每一列求均值colMeans(),
    # 最后矩阵列均值画图
    df %>% select(starts_with("w")) %>% `*`(2) %>% 
      unlist() %>% matrix(nrow=2) %>% colMeans() %>% plot()
    plot(colMeans(matrix(unlist(2*select(df,starts_with("w"))),
           nrow=2)))
    w <- select(df,starts_with("w"))
    v <- unlist(w*2)
    m <- matrix(v,nrow=2)
    plot(colMeans(m))
    
    # 一次使用多个函数计算
    df$weight %>% {c(min(.), mean(.), max(.))} %>% floor 
    # 想作为函数第二个参数时,可以用.代替
    2 %>% head(df,.)
    # 将得到的结果赋值
    a <- df %>% .$name2 %>% grep("a",.)
    

    R数据处理|基础篇(二) baidu:dplyr包5个主要函数,tidyr包中四个主要函数,reshape2包中的融合-重铸两个函数

    数据框合并

    # load package
    library(dplyr) # 高速处理数据,取代R自带的一些函数,代码简单易记
    library(tidyr) # 提供一些其他功能
    library(reshape2)
    

    列相同的两个数据框可以直接纵向接在一起,行相同的两个数据框也可以横向接在一起。

    name1 <- c("Bob","Mary","Jane","Kim")
    name2 <- c("Bob","Mary","Kim","Jane")
    weight <- c(60,65,45,55)
    height <- c(170,165,140,135)
    birth <- c("1990-1","1980-2","1995-5","1996-4")
    accept <- c("no","ok","ok","no")
    df1 <- data.frame(name1,weight,height)
    df2 <- data.frame(name2,birth,accept)
    rbind(df1,df1[c(2,4),]) # 行合并,需要列数、列名相同
    cbind(df1,df2) # 列合并,需要行数相同
    data.frame(df1,df2) # 建立数据框,达到相同的效果
    # dplyr包中高效合并
    bind_rows(df1,df1[c(2,4),])  
    bind_cols(df1,df2)
    

    merge合并

    当两个数据框中有一列表示相同的含义,其他列不同时,可以按照这一列merge起来。

    比如拿到两张表,分别对应两个数据框, 一个记录了公司每个员工的体重,一个记录了公司每个员工的身高, 他们有相同的姓名一列,我们就可以把两个数据框融合成为一个带有姓名、身高、体重的数据框。

    有的人可能会问,为什么不直接横向拼在一起,再把相同的名字列去掉? 是因为如果两个数据框的名字顺序不一样,或者名字不是完全相同,这样做就不行了。 我们来看下面的例子,

    # 先创建数据框
    name1 <- c("Bob","Mary","Jane","Kim","Smith")
    weight <- c(60,65,45,55,60)
    name2 <- c("Bob","Mary","Kim","Jane","Eric")
    height <- c(170,165,140,135,170)
    df11 <- data.frame(name1,weight,stringsAsFactors=F) # 加这个参数是防止字符串自动转化为因子
    df33 <- data.frame(name1,height,stringsAsFactors=F)
    df22 <- data.frame(name2,height,stringsAsFactors=F) # 成员与前面不完全一样
    # 先使用基础的merge函数
    merge(df11,df33) # 自动根据相同的列名匹配
    merge(df11,df22,by.x="name1",by.y="name2") # 没有相同的列名则指定根据这两列融合
    # 上面默认保留了df11和df22共有的行
    merge(df11,df22,by.x="name1",by.y="name2",all=T) # 保留所有出现过的行,没有的显示NA
    merge(df11,df22,by.x="name1",by.y="name2",all.x=T) # 保留所有x的行
    merge(df11,df22,by.x="name1",by.y="name2",all.y=T) # 保留所有y的行
    # 下面使用dplyr包
    inner_join(df11,df33) # 自动根据相同的列名匹配 
    full_join(df11,df22,by=c("name1"="name2"))
    left_join(df11,df22,by=c("name1"="name2")) # 只保留前者的行
    right_join(df11,df22,by=c("name1"="name2")) # 只保留后者的行
    semi_join(df11,df22,by=c("name1"="name2")) # 保留共有的行,同时只返回前者的列
    anti_join(df11,df22,by=c("name1"="name2")) # 返回后者没有的前者的行,同时只返回前者的列
    

    计算并增加行列

    # 创建数据框
    name1 <- c("Bob","Mary","Jane","Kim")
    weight <- c(60,65,45,55)
    height <- c(170,165,140,135)
    df1 <- data.frame(name1,weight,height)
    # R基础函数
    df2 <- transform(df1,BMI=weight/height^2) # 第一种方法
    df1$BMI <- df1$weight/df1$height^2 # 第二种方法, 每一步都要$,很麻烦
    # 使用dplyr包中的函数
    mutate(df1,BMI=weight/height^2)
    
    apply(df1[,-1],2,mean) # R基础函数
    # dplyr包中的summarise系列函数
    summarise(df1,arv_weight=mean(weight),arv_height=mean(height))
    # 上面这种方式是一般人都会用的,但是如果没有看过dplyr包的文档,就不知道还有summarise_all等函数。
    # 当需要对每列都进行计算时,或者选择某一些列计算,只是summarise一个一个指定就会非常麻烦。
    # 下面我们介绍一些批量筛选计算的函数
    # 为了更好地说明问题,我们改一下数据框
    name1 <- c("Bob","Mary","Jane","Kim")
    weight <- c(60,65,45,55)
    height <- c(170,165,140,135)
    weta <- 1:4
    df1 <- data.frame(name1,weight,height,weta)
    summarise_all 和 summarise_if
    # 对所有列进行计算或者根据列的数据类型选择计算
    summarise(df1,avg_weight=mean(weight),avg_height=mean(height)) # 很麻烦地每个都指定
    summarise_all(df1[-1],mean) # 对选出来的所有列都进行计算
    summarise_if(df1,is.numeric,mean) # 检验出所有是数值的列,全部求均值
    summarise_at配合vars的用法
    # 筛选出符合条件的列名对应的列
    summarise_at(df1,vars(weight,height,weta),mean) # 配合vars函数,一次选择多列
    summarise_at(df1,vars(weight:weta),mean) # 从哪到哪
    u <- c("weight","height")
    summarise_at(df1,vars(one_of(u)),mean) # 可以接字符串向量
    summarise_at(df1,u,mean) # 也可以直接接字符串向量
    summarise_at(df1,u,mean,trim=1) # mean的参数可以接在后面
    summarise_at(df1,vars(contains("eig")),mean) # 匹配含有的
    summarise_at(df1,vars(matches(".t.")),mean) # 使用正则表达式
    summarise_at(df1,vars(starts_with("w")),mean) # 匹配以此为开头的
    summarise_at(df1,vars(ends_with("ht")),mean) # 匹配以此为结尾的
    summarise_at(df1[,-1],vars(everything()),mean) # 选择所有列
    # funs的用法
    summarise_all(df1[,-1],funs(mean,sum))
    summarise_all(df1[,-1],funs(sum(.*2))) # 数据用.表示
    summarise_all(df1[,-1],funs(medi=median)) # 指定得到的列后缀名
    summarise_all(df1[,-1],funs("in"=median)) # 或者加引号
    mutate_all(df1[,-1],funs(.^2))
    # 结合使用
    summarise_if(df1,is.numeric,funs(mean,sum))
    summarise_at(df1,vars(ends_with("t")),funs(mean,sum))
    
    # 首先创建我们需要的数据集
    name1 <- c("Bob","Mary","Jane","Kim")
    weight <- c(60,65,45,55)
    height <- c(170,165,140,135)
    accept <- c("no","ok","ok","no")
    df <- data.frame(name1,weight,height,accept)
    # R基础函数
    tapply(df$height,df$accept,mean)  # 使用tapply函数,按照accept分类
    with(df,{ # 使用aggregate函数
      aggregate(height,by=list(accept),FUN=mean)
    # 使用dplyr包中的函数
    group_df <- group_by(df,accept)
    summarise(group_df,arv_height=mean(height),count=n()) # 其中n()是查数的意思
    # 使用扩展函数
    summarise_all(group_df[,-1],mean)
    summarise_if(group_df,is.numeric,mean)
    summarise_at(group_df,vars(contains("eigh")),funs(sum,mean))
    # dplyr包中的主要功能我们就讲到这里,除了以上功能,这个包还改写了很多基础函数.
    # 使其使用更方便,运行速度更快,感兴趣的读者可以查看帮助文档自行学习。
    

    使用reshape2包和tidyr包分别完成融合重铸功能。

    names(airquality) <- tolower(names(airquality))
    View(airquality)
    aqm <- melt(airquality, id=c("month", "day"), na.rm=TRUE) # 除了month和day两列,其他列摞起来,为了等长,m和d列循环对齐
    dcast(aqm, day + variable ~ month) # 保持day和variable不变,month中的元素分类映射到列上去
    dcast(aqm, variable + day ~ month) # 换一下顺序,重复的variable连在一起,对应不一样的day,这样的方式排列
    dcast(aqm, day ~ variable + month) # 只保留day列
    # 加入计算
    dcast(aqm, day ~ month, mean) # 没出现的那个变量被平均掉了
    # dcast 和 acast区别
    dcast(aqm, variable + month ~ day) 
    acast(aqm, variable + month ~ day) 
    # acast和dcast的功能基本上相同,只是dcast会把分组信息作为一列或几列显示,
    # 而acast会将其作为行名
    acast(aqm, day ~ month, mean) # 保留的列作为合并在一起作为列名
    acast(aqm, variable ~ month ~ day) 
    # acast 多出来的功能,生成一个三维数组,
    # 按照day的值分成31个矩阵
    # tidyr包-有融合和重铸的函数,但是在重铸方面功能弱一些
    aqg <- gather(airquality,group,value,ozone:temp) # 融合,和reshape2的不同在于输入的是被转换的列
    spread(aqg,group,value) # 还原
    spread(aqg,month,value) # 输入要被转化到列名的列和值,好像一次只能转化一列作为列名
    

    融合重铸的应用

    让我们把融合重铸计算实现的功能和分组计算做一下对比。 假设我们拿到的数据是下面这个样子的。按照月日,分不同组别汇总在一起的两列变量值

    df <- mutate(aqm, newvalue = value+rnorm(2,0,50))
    colnames(df) <- c("month","day","group","value1","value2")
    View(df) # 我们可以看一看现在拿到的数据
    

    我们首先实现如下功能:

  • 根据group分组计算两个value的均值
  • 根据month和group分组计算两个value的均值
  • 根据month和group分组计算每组个数
  • 使用分组计算来实现

    # 根据group分组计算两个value的均值
    df_grp1 <- group_by(df,group)
    summarise_at(df_grp1,vars(value1,value2),mean)
    # 根据month和group分组计算两个value的均值
    df_grp2 <- group_by(df,month,group)
    summarise_at(df_grp2,vars(value1,value2),mean)
    # 根据month和group分组计算每组个数
    summarise(df_grp2,count=n())
    

    使用融合重铸来实现

    df_melt <- melt(df,id=c("month","day","group"))
    # 根据group分组计算两个value的均值
    dcast(df_melt, group ~ variable, mean)
    # 根据month和group分组计算两个value的均值
    dcast(df_melt, month + group ~ variable, mean)
    # 根据month和group分组计算每组个数
    dcast(df_melt, month + group ~ variable, length)
    

    从上面来看,实现分组计算的功能二者没有太大区别,毕竟这就是分组计算本身在做的事情,不过当需要按照多种分组来计算时,融合重铸不需要重新设置组别,显然会更方便。

    不过融合重铸也要注意一点,如果数据列数非常多,而且有的是字符串,或者有的列不是你需要计算的,要事先只提取出你需要的,再融合重铸。

    下面我们说一说融合重铸擅长的部分

    如果要不区分value1和value2,算整体按照month和group分组后的均值 上面计算结果值是一个矩阵,想要把数值用一列表示 按照月份拆分成多个矩阵,每一个矩阵表示group和日期的对应

    # 如果要不区分value1和value2,算整体按照month和group分组后的均值
    (mg <- dcast(df_melt, month ~ group , mean))# 上面计算结果值是一个矩阵,想要用一列表示
    melt(mg, id="month")
    # 按照月份拆分成多个矩阵,每一个矩阵表示group和日期的对应
    u <- acast(df_melt, group ~ day ~ month) # 使用acast返回一个三维数组
    

    拆分合并列

    我们现在要把一列这种类型”1990-1”的数据拆分成两列”1990”和”1”这样的数据, 使用tidyr包中的separate函数

    library(tidyr)
    name1 <- c("Bob","Mary","Jane","Kim")
    birth <- c("1990-1","1980-2","1995-5","1996-4")
    df <- data.frame(name1, birth)
    (df1 <- separate(df,birth,into=c("year","month"),sep="-"))
    separate_rows(df,birth,sep="-") # 拆分完放在一列里面显示
    # 其实separate_rows相当于使用separate之后进行了融合,再更换一下顺序
    separate(df,birth,into=c("year","month"),sep="-") %>% gather(group,birth,year:month)
    

    tidyr包中很多函数都是成对出现的,unite 函数是和separate函数反向的函数,可以将它得到的结果还原

    unite(df1,birth,year,month,sep="-")
    

    到这里,我们就把数据处理的整体框架讲述了一遍. 主要针对数据的计算与变形,覆盖了dplyr tidyr reshape2包的使用方法。

    本专题下一篇,我们会使用data.table包来重新完成这整个框架

    About Hadley

    Hadley Wickham 是 Rstudio 首席数据科学家,他写了很多非常著名的R包,为R语言做出了非常大贡献。 rstudio网站上列出了一些非常著名的R包,我们会发现有一大半都是Hadley写的。

    最著名的当然是 ggplot2 作图包了,有些人认为这是自己不想离开R转向python的唯一原因。 用简单的代码做出精美的图,强大的功能,专门为统计分析作图提供便捷,确实让人爱不释手。 不过这个包学起来却不是那么容易,本专栏之后也会开出专题专门讲这个包。

    数据分析包,也就是本专栏主要介绍的 reshape2 dplyr tidyr 包. 这些包可以高效处理数据,代码简洁,功能强大。 而且可以和 ggplot2 一起使用,形成了一整个处理数据并可视化的生态。

    时间处理包 lubridate 包、字符串处理 stringr包 读取数据 readr 包 readxl 包 haven 包.

    除此之外,为了帮助完善R语言的生态,帮助其他人更加便捷地开发R包,他还写了 devtools 等包

    Advanced R 想要深入理解R语言可以读这本书,读过之后会发现之前遇到的很多无法解决的问题都豁然开朗。本书已经有了中文版,《r语言高级程序设计》

    R for Data Science 这是Hadley的新书. 本书结合他的 数据分析和ggplot2包 ,讲述了数据分析的理念和流程, 读完可以对统计分析有更深入的了解,也可以更灵活地使用他开发的R包

    R packages 本书我还没有读过,不做介绍。上面三本都有英文版免费放在网站上

    ggplot2: elegant graphics for data analysis 这本书主要讲述 ggplot2 包的涉及理念及用法. 想要更熟练掌握 ggplot2 包的话建议阅读.

     
    推荐文章