如果说R语言学习者会有的书,大概率会有这一本。本书可以说是R语言学习者和使用者的一个分水岭,在此之前是各种copy调试,在此之后开始用R做一些自己的事情。其实这样的书可以罗列出好几本:

  • ggplot2 数据分析与图形艺术(ggplot2 Elegant Graphics for Data Analysis)
  • R语言实战(RinAction)
  • R语言核心技术手册(RinaNutshell)
  • R语言数据科学(R for data science)
  • 高级R语言编程指南( Advanced R)
  • 这些书每看完一本,都会对R的特性有进一步的理解。《R语言编程艺术》这本书是买的比较早的了,之前也泛泛地翻过,主要是对R的特点有个相对系统的理解。从目录导图中不难看出,这本书涉及的内容是广泛的,如果恰逢其时,你会觉得这本书就是为当下的你写的——就像第九十八个阶梯,早一步的话望而却步,晚一步的话只只剩下蓦然回首。所以这是一本时长拿来看看的R语言书籍:说不定哪一次就对上号了。

    本书的特点主要有:

  • 第七章是这本书的核心
  • 最主要的特点是有大量的演示案例,虽然大部分的主题在 R语言数据科学 或者R语言核心技术手册均有涉及,但是讲述的方法不同,往往乐意无穷《R语言数据科学》这本书像是哈德利·威克汉姆用自己定义的R语言在讲述这些知识点(哈德利·威克汉姆重新定义了很多),R语言核心技术手册又显得太厚了,让人像面对 R语言实战 一样,望而却步。

    我觉得第七章<R语言编程结构>是这本书的核心,这也许和目前我的水平有关:开始关注函数的实现与组织。这一章探讨了编程中的控制结构以及函数的实现,环境作用域等,函数编程的基本概念。在这一章中,我们可以体会到用R语言和会编程其实是两件事。

    像编程这样的书籍,读一遍是远不够的,因为我们系要理解的不是人类语言的部分,而是非人的代码部分,不仅要理解更是要能运用。这也是做纸质书的好处,可以在代码上做注释,写下自己的惊叹和感悟。

    另外,本书值得学习的是关于debug的部分,在做调包侠的时候很少用到这项技能,遇到问题找R包换R包安R包,但是如果是自己写函数了,或者有的R包还不太成熟的话,就需要我们来为代码debug。这部分内容,对很多已经是调包侠的人来说是一个进阶的突破口。

    # class "ut", compact storage of upper-triangular matrices
    # utility function, returns 1+...+i
    sum1toi <- function(i) return(i*(i+1)/2)
    # create an object of class "ut" from the full matrix inmat (0s included)
    ut <- function(inmat) {
        n <- nrow(inmat)
        rtrn <- list()  # start to build the object  
        class(rtrn) <- "ut"
        rtrn$mat <- vector(length=sum1toi(n))  
        rtrn$ix <- sum1toi(0:(n-1)) + 1  
        for (i in 1:n) {  
            # store column i
            ixi <- rtrn$ix[i]
            rtrn$mat[ixi:(ixi+i-1)] <- inmat[1:i,i]
        return(rtrn)
    # uncompress utmat to a full matrix
    expandut <- function(utmat) {
        n <- length(utmat$ix)  # numbers of rows and cols of matrix
        fullmat <- matrix(nrow=n,ncol=n)
        for (j in 1:n) {
            # fill j-th column
            start <- utmat$ix[j]  
            fin <- start + j - 1 
            abovediagj <- utmat$mat[start:fin] # above-diag part of col j
            fullmat[,j] <- c(abovediagj,rep(0,n-j))  
        return(fullmat)
    # print matrix
    print.ut <- function(utmat) 
        print(expandut(utmat))
    # multiply one ut matrix by another, returning another ut instance;
    # implement as a binary operation
    "%mut%" <- function(utmat1,utmat2) {
        n <- length(utmat1$ix)  # numbers of rows and cols of matrix
        utprod <- ut(matrix(0,nrow=n,ncol=n))  
        for (i in 1:n) {  # compute col i of product
            # let a[j] and bj denote columns j of utmat1 and utmat2, respectively, 
            # so that, e.g. b2[1] means element 1 of colument 2 of utmat2 
            # then column i of product is equal to 
            #    bi[1]*a[1] + ... + bi[i]*a[i]
            # find index of start of column i in utmat2
            startbi <- utmat2$ix[i] 
            # initialize vector that will become bi[1]*a[1] + ... + bi[i]*a[i]
            prodcoli <- rep(0,i)
            for (j in 1:i) {  # find bi[j]*a[j], add to prodcoli  
                startaj <- utmat1$ix[j] 
                bielement <- utmat2$mat[startbi+j-1]
                prodcoli[1:j] <- prodcoli[1:j] + 
                    bielement * utmat1$mat[startaj:(startaj+j-1)]
            # now need to tack on the lower 0s
            startprodcoli <- sum1toi(i-1)+1
            utprod$mat[startbi:(startbi+i-1)] <- prodcoli
        return(utprod)
    test <- function() {
        utm1 <- ut(rbind(1:2,c(0,2)))
        utm2 <- ut(rbind(3:2,c(0,1)))
        utp <- utm1 %mut% utm2
        print(utm1)
        print(utm2)
        print(utp)
        utm1 <- ut(rbind(1:3,0:2,c(0,0,5)))
        utm2 <- ut(rbind(4:2,0:2,c(0,0,1)))
        utp <- utm1 %mut% utm2
        print(utm1)
        print(utm2)
        print(utp)
    test()