3.6 检查变量

当在控制台输入一个运算或者变量时,结果就被打印出来,因为R隐式调用了对象的print方法。

注意

对以下术语稍作解释:大多情况下,“方法”(method)和“函数”(function)是可以互换的。有时,R中的函数也称为面向对象中的方法。不同类型的对象有不同版本的print函数,这使得矩阵与向量的打印方法不同,这就是谈到“打印方法”的原因。

所以,在命令提示符下输入1 + 1print( 1 + 1)一样。

但是,对于内循环或函数来说4,自动打印功能不起作用,我们必须显式地调用print

4 除非函数返回了值。

  1. ulams_spiral <- c(1, 8, 23, 46, 77) # 参考http://oeis.org/A033951
  2. for(i in ulams_spiral) i # 啊哦, 值没有打印出来
  3. for(i in ulams_spiral) print(i)
  4. ## [1] 1
  5. ## [1] 8
  6. ## [1] 23
  7. ## [1] 46
  8. ## [1] 77

如果你是在终端而不是在GUI或IDE上运行R,在某些系统上这个问题的确存在。在这种情况下,你就一直需要显式调用print函数。

大部分print函数的实现建立在调用底层的cat函数上。虽然你可能永远无需直接调用cat(与之对应的用户级命令是printmessage),但是仍应对此有所了解,以便在需要时亲自编写print函数5

5 也许就像在练习16-3中那样。

注意

ccat函数都是concatenate的缩写,但它们的作用完全不同!cat是以Unix中的函数命名的。

除了查看变量的打印输出,最好也能看到某种程度的对象汇总信息。summary函数就能为不同的数据类型提供汇总信息。例如,数值变量会被汇总统计出平均数、中位数,以及一些分位数(quantile)。在下例中,runif函将数生成30个均匀分布于0和1之间的随机数:

  1. num <- runif(30)
  2. summary(num)
  3. ## Min. 1st Qu. Median Mean 3rd Qu. Max.
  4. ##0.0211 0.2960 0.5060 0.5290 0.7810 0.9920

类别变量和逻辑向量将根据每个值的计算进行汇总。在下例中,letters是一个内置的常数,它包含了从a到z的小写值(大写的LETTERS则包括了类似的从A到Z的大写值)。这里letters[ 1:5]用索引限制letters的范围为从a到e。sample函数使用重复抽样replace随机抽样30次:

  1. fac <- factor(sample(letters[1:5], 30, replace = TRUE))
  2. summary(fac)
  3. ## a b c d e
  4. ## 6 7 5 9 3
  5. bool <- sample(c(TRUE, FALSE, NA), 30, replace = TRUE)
  6. summary(bool)
  7. ## Mode FALSE TRUE NA's
  8. ## logical 12 11 7

多维对象与矩阵及数据框一样,都是通过列来汇总的(第4章和第5章将做更详细的讨论)。我们在下面创建的数据框dfr非常大,显示出来足足有30行。对于这样的庞然大物 6,用head函数即可仅显示它的前几行(默认为6行):

6 现在,30行的数据算不上是“大数据”,但在打印时它仍能占满整个屏幕。

  1. dfr <- data.frame(num, fac, bool)
  2. head(dfr)
  3. ## num fac bool
  4. ## 1 0.47316 b NA
  5. ## 2 0.56782 d FALSE
  6. ## 3 0.46205 d FALSE
  7. ## 4 0.02114 b TRUE
  8. ## 5 0.27963 a TRUE
  9. ## 6 0.46690 a TRUE

数据框的summary函数就像为每列单独调用summary一样:

  1. summary(dfr)
  2. ## num fac bool
  3. ## Min. :0.0211 a:6 Mode :logical
  4. ## 1st Qu.:0.2958 b:7 FALSE:12
  5. ## Median :0.5061 c:5 TRUE :11
  6. ## Mean :0.5285 d:9 NA's :7
  7. ## 3rd Qu.:0.7808 e:3
  8. ## Max. :0.9916

类似地,str函数能显示对象的结构。对向量来说,它并非很有趣(因为它们太简单了),但str对数据框和嵌套列表非常有用:

  1. str(num)
  2. ## num [1:30] 0.4732 0.5678 0.462 0.0211 0.2796 ...
  3. str(dfr)
  4. ## 'data.frame': 30 obs. of 3 variables:
  5. ## $ num : num 0.4732 0.5678 0.462 0.0211 0.2796 ...
  6. ## $ fac : Factor w/ 5 levels "a","b","c","d",..: 2 4 4 2 1 1 4 2 1 4 ...
  7. ## $ bool: logi NA FALSE FALSE TRUE TRUE TRUE ...

如前所述,每个类都有自己的打印(print)方法,以此控制如何显示到控制台。有时,这种打印模糊了其内部结构,或忽略了一些有用的信息。用unclass函数可绕开这一点,显示变量是如何构建的。例如,对因子调用unclass函数会显示它仅是一个整数(integer)向量,拥有一个叫levels的属性:

  1. unclass(fac)
  2. ## [1] 2 4 4 2 1 1 4 2 1 4 3 3 1 5 4 5 1 5 1 2 2 3 4 2 4 3 4 2 3 4
  3. ## attr(,"levels")
  4. ## [1] "a" "b" "c" "d" "e"

稍后我们会讨论属性,而现在须了解的是,attributes函数能显示当前对像的所有属性列表:

  1. attributes(fac)
  2. ## $levels
  3. ## [1] "a" "b" "c" "d" "e"
  4. ##
  5. ## $class
  6. ## [1] "factor"

为了可视化诸如矩阵和数据框之类的二维变量,View(请注意大写字母“V”)函数会把变量(只读的)显示为电子表格(spreadsheet)。editfix函数的工作方式与View类似,但它允许手动更改数据值。虽然这听似更实用,但以这种方式编辑数据却是个无比糟糕的主意,因为我们会失去所有的可追溯性而无法追踪数据的出处。最好的方式还是使用编程来编辑数据:

  1. View(dfr) #不允许更改
  2. new_dfr <- edit(dfr)   #更改将保存于new_dfr
  3. fix(dfr)   #更改将保存于dfr

一个好方法是结合Viewhead函数来查看数据框的前几行:

  1. View(head(dfr, 50)) #查看前 50行