blob: b00568f472179761bb3fdedc2381d07b651962e6 [file] [log] [blame]
# File src/library/base/R/summary.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2018 The R Core Team
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License is available at
# https://www.R-project.org/Licenses/
summary <- function (object, ...) UseMethod("summary")
summary.default <- function(object, ..., digits, quantile.type = 7)
{
if(is.factor(object))
return(summary.factor(object, ...))
else if(is.matrix(object)) {
if(missing(digits))
return(summary.matrix(object, quantile.type=quantile.type, ...))
else
return(summary.matrix(object, digits = digits, quantile.type=quantile.type, ...))
}
value <- if(is.logical(object)) # scalar or array!
c(Mode = "logical",
{tb <- table(object, exclude = NULL, useNA = "ifany") # incl. NA s
if(!is.null(n <- dimnames(tb)[[1L]]) && any(iN <- is.na(n)))
dimnames(tb)[[1L]][iN] <- "NA's"
tb
})
else if(is.numeric(object)) {
nas <- is.na(object)
object <- object[!nas]
qq <- stats::quantile(object, names = FALSE, type = quantile.type)
qq <- c(qq[1L:3L], mean(object), qq[4L:5L])
if(!missing(digits)) qq <- signif(qq, digits)
names(qq) <- c("Min.", "1st Qu.", "Median", "Mean", "3rd Qu.", "Max.")
if(any(nas))
c(qq, "NA's" = sum(nas))
else qq
} else if(is.recursive(object) && !is.language(object) &&
(n <- length(object))) { # do not allow long dims
sumry <- array("", c(n, 3L), list(names(object),
c("Length", "Class", "Mode")))
ll <- numeric(n)
for(i in 1L:n) {
ii <- object[[i]]
ll[i] <- length(ii)
cls <- oldClass(ii)
sumry[i, 2L] <- if(length(cls)) cls[1L] else "-none-"
sumry[i, 3L] <- mode(ii)
}
sumry[, 1L] <- format(as.integer(ll))
sumry
}
else c(Length = length(object), Class = class(object), Mode = mode(object))
class(value) <- c("summaryDefault", "table")
value
}
format.summaryDefault <- function(x, digits = max(3L, getOption("digits") - 3L), ...)
{
xx <- x
if(is.numeric(x) || is.complex(x)) {
finite <- is.finite(x)
xx[finite] <- zapsmall(x[finite])
}
class(xx) <- class(x)[-1]
m <- match("NA's", names(x), 0)
if(inherits(x, "Date") || inherits(x, "POSIXct")) {
if(length(a <- attr(x, "NAs")))
c(format(xx, digits=digits, ...), "NA's" = as.character(a))
else format(xx, digits=digits)
} else if(m && !is.character(x))
xx <- c(format(xx[-m], digits=digits, ...), "NA's" = as.character(xx[m]))
else format(xx, digits=digits, ...)
}
print.summaryDefault <- function(x, digits = max(3L, getOption("digits") - 3L), ...)
{
xx <- x
if(is.numeric(x) || is.complex(x)) {
finite <- is.finite(x)
xx[finite] <- zapsmall(x[finite])
}
class(xx) <- class(x)[-1] # for format
m <- match("NA's", names(xx), 0)
if(inherits(x, "Date") || inherits(x, "POSIXct")) {
xx <- if(length(a <- attr(x, "NAs")))
c(format(xx, digits=digits), "NA's" = as.character(a))
else format(xx, digits=digits)
print(xx, digits=digits, ...)
return(invisible(x))
} else if(m && !is.character(x))
xx <- c(format(xx[-m], digits=digits), "NA's" = as.character(xx[m]))
print.table(xx, digits=digits, ...)
invisible(x)
}
summary.factor <- function(object, maxsum = 100L, ...)
{
nas <- is.na(object)
ll <- levels(object)
if(ana <- any(nas)) maxsum <- maxsum - 1L
tbl <- table(object)
tt <- c(tbl) # names dropped ...
names(tt) <- dimnames(tbl)[[1L]]
if(length(ll) > maxsum) {
drop <- maxsum:length(ll)
o <- sort.list(tt, decreasing = TRUE)
tt <- c(tt[o[ - drop]], "(Other)" = sum(tt[o[drop]]))
}
if(ana) c(tt, "NA's" = sum(nas)) else tt
}
summary.matrix <- function(object, ...) {
## we do want this changed into separate columns, so use data.frame method
summary.data.frame(as.data.frame.matrix(object), ...)
}
summary.data.frame <-
function(object, maxsum = 7L, digits = max(3L, getOption("digits") - 3L), ...)
{
ncw <- function(x) {
z <- nchar(x, type="w")
if (any(na <- is.na(z))) {
# FIXME: can we do better
z[na] <- nchar(encodeString(z[na]), "b")
}
z
}
# compute results to full precision.
z <- lapply(X = as.list(object), FUN = summary,
maxsum = maxsum, digits = 12L, ...)
nv <- length(object)
nm <- names(object)
lw <- numeric(nv)
nr <- if (nv)
max(vapply(z, function(x) NROW(x) + !is.null(attr(x, "NAs")), integer(1)))
else 0
for(i in seq_len(nv)) {
sms <- z[[i]]
if(is.matrix(sms)) {
## need to produce a single column, so collapse matrix
## across rows
cn <- paste(nm[i], gsub("^ +", "", colnames(sms), useBytes = TRUE),
sep=".")
tmp <- format(sms)# <- digits = ?? --currently take getOption("digits") !!!
if(nrow(sms) < nr)
tmp <- rbind(tmp, matrix("", nr - nrow(sms), ncol(sms)))
sms <- apply(tmp, 1L, function(x) paste(x, collapse=" "))
## produce a suitable colname: undoing padding
wid <- sapply(tmp[1L, ], nchar, type="w") # might be NA
blanks <- paste(character(max(wid)), collapse = " ")
wcn <- ncw(cn)
pad0 <- floor((wid - wcn)/2)
pad1 <- wid - wcn - pad0
cn <- paste0(substring(blanks, 1L, pad0), cn,
substring(blanks, 1L, pad1))
nm[i] <- paste(cn, collapse=" ")
} else {
sms <- format(sms, digits = digits) # may add NAs row
lbs <- format(names(sms))
sms <- paste0(lbs, ":", sms, " ")
lw[i] <- ncw(lbs[1L])
length(sms) <- nr
}
z[[i]] <- sms
}
if (nv) {
z <- unlist(z, use.names=TRUE)
dim(z) <- c(nr, nv)
if(anyNA(lw))
warning("probably wrong encoding in names(.) of column ",
paste(which(is.na(lw)), collapse = ", "))
blanks <- paste(character(max(lw, na.rm=TRUE) + 2L), collapse = " ")
pad <- floor(lw - ncw(nm)/2)
nm <- paste0(substring(blanks, 1, pad), nm)
dimnames(z) <- list(rep.int("", nr), nm)
} else {
z <- character()
dim(z) <- c(nr, nv)
}
attr(z, "class") <- c("table") #, "matrix")
z
}