1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
#' @title Rotate a data frame
#' @name data_rotate
#'
#' @description
#' This function rotates a data frame, i.e. columns become rows and vice versa.
#' It's the equivalent of using `t()` but restores the `data.frame` class,
#' preserves attributes and prints a warning if the data type is
#' modified (see example).
#'
#' @param data A data frame.
#' @param rownames Character vector (optional). If not `NULL`, the data frame's
#' rownames will be added as (first) column to the output, with `rownames`
#' being the name of this column.
#' @param colnames Logical or character vector (optional). If `TRUE`, the values
#' of the first column in `x` will be used as column names in the rotated data
#' frame. If a character vector, values from that column are used as column
#' names.
#' @param verbose Toggle warnings.
#'
#' @inherit data_rename seealso
#'
#' @return A (rotated) data frame.
#'
#' @examples
#' x <- mtcars[1:3, 1:4]
#'
#' x
#'
#' data_rotate(x)
#' data_rotate(x, rownames = "property")
#'
#' # use values in 1. column as column name
#' data_rotate(x, colnames = TRUE)
#' data_rotate(x, rownames = "property", colnames = TRUE)
#'
#' # use either first column or specific column for column names
#' x <- data.frame(a = 1:5, b = 11:15, c = 21:25)
#' data_rotate(x, colnames = TRUE)
#' data_rotate(x, colnames = "c")
#'
#' @export
data_rotate <- function(data, rownames = NULL, colnames = FALSE, verbose = TRUE) {
# copy attributes
attr_data <- attributes(data)
# check if first column has column names to be used for rotated data
if (isTRUE(colnames)) {
colnames <- data[[1]]
data <- data[-1]
} else if (!is.null(colnames) && is.character(colnames) && colnames %in% colnames(data)) {
cn_col <- which(colnames(data) == colnames)
colnames <- data[[colnames]]
data <- data[-cn_col]
} else {
colnames <- row.names(data)
}
# warning after possible removal of columns
if (verbose && insight::n_unique(vapply(data, typeof, FUN.VALUE = character(1L))) > 1L) {
insight::format_warning("Your data frame contains mixed types of data. After transposition, all variables will be transformed into characters.") # nolint
}
# rotate data frame by 90 degrees
out <- as.data.frame(t(as.data.frame(data)))
# add column names, if requested
if (!is.null(colnames)) {
# check if we have correct length of column names
if (length(colnames) != ncol(out)) {
insight::format_warning(
"Length of provided column names does not match number of columns. No column names changed."
)
} else {
colnames(out) <- colnames
}
}
# add rownames as a new column, if requested
if (!is.null(rownames)) out <- rownames_as_column(out, var = rownames)
out <- .replace_attrs(out, attr_data)
out
}
#' @rdname data_rotate
#' @export
data_transpose <- data_rotate
|