# File src/library/base/R/summary.R # Part of the R package, https://www.R-project.org # # Copyright (C) 1995-2022 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", allowNA=TRUE) 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 }