网络包更改了字符向量摘要的行为,打破了 summary.data.frame(打印所有值,以 NULL: 开头)

Network package changes behaviour of summary for character vectors, breaking summary.data.frame (all values are printed, preceded by NULL: )

加载 network 包后,summary.data.frame 函数出现问题:如果出现 class "character" 列,而不是通常的输出, summary 将打印 all 行的值,并在前面加上 NULL:。这是一个玩具示例:

test <- data.frame(a=c("some", "char", "vector", "with", 
                       "many", "many", "words"),
                   b=1:7, stringsAsFactors = FALSE)

# Expected behaviour

summary(test$a)

##    Length     Class      Mode 
##         7 character character

summary(test)

##       a                   b      
##  Length:7           Min.   :1.0  
##  Class :character   1st Qu.:2.5  
##  Mode  :character   Median :4.0  
##                     Mean   :4.0  
##                     3rd Qu.:5.5  
##                     Max.   :7.0

library("network")

## network: Classes for Relational Data
## Version 1.13.0 created on 2015-08-31.
## ...

# Behavior after loading network:

summary(test$a)

##   char   many   some vector   with  words 
##      1      2      1      1      1      1

summary(test)

##     a                b      
##  NULL:some     Min.   :1.0  
##  NULL:char     1st Qu.:2.5  
##  NULL:vector   Median :4.0  
##  NULL:with     Mean   :4.0  
##  NULL:many     3rd Qu.:5.5  
##  NULL:many     Max.   :7.0  
##  NULL:words

请注意,输出包括字符向量的所有元素,包括重复项,因此您将获得 1000 行的 1000 行摘要, 这使得汇总功能无法使用。 此行为在分离网络包后仍然存在,直到重新启动新的 R 会话。

出了什么问题:通常 UseMethod("summary") 字符向量调用 summary.default,它会产生正常输出,其中有 names

summary.default(test$a)

##    Length     Class      Mode 
##         7 character character

names(summary.default(test$a))

## [1] "Length" "Class"  "Mode"

网络包定义了一个summary.character函数,它简单地向字符对象添加一个"summary.character"class,这样它的打印调用network::print.summary.character,它产生table 最多 10 个最常见的值。对象本身没有变化,所以它的 namesNULL

summary.character

## function (object, ...) 
## {
##     class(object) <- c("summary.character", class(object))
##     object
## }
## <environment: namespace:network>

summary.character(test$a)

##   char   many   some vector   with  words 
##      1      2      1      1      1      1

names(summary.character(test$a))

## NULL

class(summary.character(test$a))

## [1] "summary.character" "character"

length(summary.character(test$a))

## [1] 7

as.character(summary.character(test$a))

## [1] "some"   "char"   "vector" "with"   "many"   "many"   "words"

问题出在summary.data.frame中的这三行:

        sms <- format(sms, digits = digits)
        lbs <- format(names(sms))
        sms <- paste0(lbs, ":", sms, "  ")

它位于列的 for 循环内,其中 sms 是当前列的 summary 的输出。对于 summary.character 的输出,sms 实际上是整列,而 names(sms)NULL,因此出现问题。

问题的核心原因在于summary.character returns 原始对象,而不是其委托给print.summary.character 的摘要表示。 summary.data.frame 只是将其与其他摘要一起粘贴,转储整个专栏。

任何关于如何在不深入研究 network 的源代码的情况下解决此问题的想法将不胜感激。

我找到了一个解决方法,不幸的是,它通过定义一个函数 format.summary.character 来恢复内部代码的预期行为,从而更多地涉及 "polluting" R 命名空间(引用@steveb 的评论) summary.data.frame。该函数的灵感来自 format.factor:

format.summary.character <- function(x, ...) {
    s <- summary.default(as.character(x), ...)
    format(structure(as.character(s), names = names(s), dim = dim(s), 
                     dimnames = dimnames(s)), ...)
}

定义此函数后,字符向量summary的输出仍然由summary.character控制,但summary.data.frame的输出恢复正常。

summary(test$a) # still calling summary.character

##   char   many   some vector   with  words 
##      1      2      1      1      1      1

summary(test)   # back to normal

##       a                   b      
##  Length:7           Min.   :1.0  
##  Class :character   1st Qu.:2.5  
##  Mode  :character   Median :4.0  
##                     Mean   :4.0  
##                     3rd Qu.:5.5  
##                     Max.   :7.0  
##