Rev 80220 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
% File src/library/stats/vignettes/reshape.Rnw% Part of the R package, https://www.R-project.org% Copyright 2021 The R Core Team% Distributed under GPL 2 or later\documentclass[a4paper]{article}\usepackage{Rd}\setlength{\parindent}{0in}\setlength{\parskip}{.1in}\setlength{\textwidth}{140mm}\setlength{\oddsidemargin}{10mm}\title{Using the reshape function}\author{The R Core Team}% \VignetteIndexEntry{Using the reshape function}% \VignettePackage{stats}\begin{document}\maketitle<<echo=FALSE, results=hide>>=library(stats)options(width = 80, continue = " ",try.outFile = stdout())@\section{Introduction}The \code{reshape()} function reshapes datasets in the so-called\sQuote{wide} format (with repeated measurements in separate columnsof the same row) to the \sQuote{long} format (with the repeatedmeasurements in separate rows), and vice versa.\code{reshape()} is a somewhat complicated function, and this vignettegives a few examples of how it can be used. Although \code{reshape()}can be used in a variety of contexts, the motivating application isdata from longitudinal studies, and the arguments of this function arenamed and described in those terms. See the documentation(\code{help(reshape)}) for background and detailed usage.For our examples, we will simulate data from a study where individualsare measured at two time points. Two of the measurements aretime-varying: height and weight, and one of the measurements istime-constant: sex.\section{Conversion from wide to long format}We first simulate data in the wide format. Data from each individualis contained in one row, with one column for time-constant variablesand multiple columns for time-varying variables. Here there are twotime points (before and after), so there are two columns for eachtime-varying variable.<<>>=set.seed(12345)n <- 5d1 <- data.frame(sex = sample(c("M", "F"), n, rep = TRUE),ht.before = round(rnorm(n, 165, 6), 1),ht.after = round(rnorm(n, 165, 6), 1),wt.before = round(rnorm(n, 80, 6)),wt.after = round(rnorm(n, 80, 6)))d1@Suppose we want to convert this dataset into the long format, with tworows for each individual, and one column for each variable (bothtime-constant and time-varying). Such a representation will need twoadditional variables to distinguish between multiple rowscorresponding to the same individual (corresponding to one row in thewide format): a time-variable and an id-variable. These will beautomatically created when converting from wide to long format.However, we do need to specify which columns in the wide formatcorrespond to the same time-varying variable(s). This is easiest to dowhen we have only one time-varying variable. Although we have two suchin our example, let us pretend that only height is time-varying. Thecorresponding columns can be specified as the \code{varying} argument.The two weight variables will then be assumed to be differenttime-constant variables, similar to sex.%% specify only ht variables as time-variables (wt variables assumed%% to be separate time constant variables)<<>>=reshape(d1, direction = "long",varying = c("ht.before", "ht.after"))@It is equivalent to specify the variables as column indices.<<>>=reshape(d1, direction = "long",varying = c(2, 3))@Note that the names of the combined variable, as well as the values ofthe time variable, are automatically detected because the names happento be \dQuote{nicely} formatted. Suppose we instead had<<>>=n <- 5d2 <- data.frame(sex = sample(c("M", "F"), n, rep = TRUE),ht_before = round(rnorm(n, 165, 6), 1),ht_after = round(rnorm(n, 165, 6), 1),wt_before = round(rnorm(n, 80, 6)),wt_after = round(rnorm(n, 80, 6)))@Modifying the previous call gives:%% Error: Fails to guess<<>>=try(reshape(d2, direction = "long",varying = c("wt_before", "wt_after")),)@This is easy to \dQuote{fix} in this case because the names are stillnicely formatted, just not using the separator that \code{reshape()}expects by default.<<>>=reshape(d2, direction = "long",varying = c("wt_before", "wt_after"), sep = "_")@A more general solution is to specify the name of the new combinedcolumn explicitly as the \code{v.names} argument.<<>>=reshape(d2, direction = "long",varying = c("wt_before", "wt_after"),v.names = "weight")@We can additionally specify the names and values of the id / timevariables as well.<<>>=reshape(d2, direction = "long",varying = c("wt_before", "wt_after"),v.names = "weight",timevar = "when", times = c("pre", "post"),idvar = "subject", ids = letters[1:n])@Note that the \code{times} argument is ignored when automatic guessingis performed, i.e., when \code{v.names} is not explicitly specified.<<>>=reshape(d2, direction = "long",varying = c("wt_before", "wt_after"), sep = "_",## v.names = "wt", # without this, 'times' is unusedtimevar = "when", times = c("pre", "post"))@So far, we have only specified one time-varying variable, but our dataactually has two. How do we specify multiple time-varying variables?This depends on whether the variable names are in a guessable format.\subsection{Explicitly specifying variables names}The general approach is to explicitly specify both \code{varying} and\code{v.names} as before. \code{v.names} should be a vector of newvariable names in the long format, and \code{varying} should either bea list, with each component giving the corresponding wide formatvariable names, or a matrix, with each row giving the correspondingwide format variable names.<<>>=reshape(d2, direction = "long",varying = list(c("ht_before", "ht_after"),c("wt_before", "wt_after")), # list formv.names = c("height", "weight"),times = c("pre", "post"))reshape(d2, direction = "long",varying = rbind(c("ht_before", "ht_after"),c("wt_before", "wt_after")), # matrix formv.names = c("height", "weight"))@The \code{times} argument has been omitted in the second exampleabove, and the default is to use sequential times. The \code{v.names}argument can be omitted as well, but the default is not generallysensible.Of course, the time and id variables can also be controlled in theusual way as long as \code{v.names} is specified.<<>>=reshape(d2, direction = "long",varying = rbind(c("ht_before", "ht_after"),c("wt_before", "wt_after")),v.names = c("height", "weight"),timevar = "when",times = c("pre", "post"),idvar = "subject",ids = letters[1:n])@\subsection{Variables names in a guessable format}Even when variable names are in a guessable format, \code{reshape()}will not try to guess if multiple time-varying variables are providedas a list or matrix. However, when the wide format variable names aresuitably formatted in the same manner for all time-varying variables,it is still possible to take advantage of automatic guessing byspecifying the \code{varying} argument as an atomic vector (of eithernames or indices) containing all time-varying columns.<<>>=reshape(d2, direction = "long",varying = c("ht_before", "ht_after","wt_before", "wt_after"), sep = "_")@The atomic vector form of \code{varying} can be combined with explicit(non-guessed) specification of \code{v.names} as well, but in thatcase, one needs to pay careful attention to the order of variablenames in \code{varying}. The following gives wrong results:<<>>=reshape(d2, direction = "long",varying = c("ht_before", "ht_after","wt_before", "wt_after"),v.names = c("height", "weight"))@The correct order requires all columns corresponding to the same timeto be contiguous; this is the same intrinsic column-major ordering inthe matrix form above. It is best to avoid the atomic vector form of\code{varying} unless \code{v.names} is being omitted.<<echo=FALSE,eval=FALSE>>=reshape(d2, direction = "long",varying = c("ht_before", "wt_before","ht_after", "wt_after"),v.names = c("height", "weight"))@\subsection{Repeated application of reshape}Just as an illustration, let us try to create an even longer datasetthat combines height and weight together in a single column.<<>>=dlong <-reshape(d2, direction = "long",varying = c("ht_before", "wt_before","ht_after", "wt_after"),v.names = c("height", "weight"),timevar = "when", times = c("pre", "post"),idvar = "subject", ids = letters[1:n])reshape(dlong, direction = "long",varying = c("height", "weight"),v.names = "combined",timevar = "what", times = c("height", "weight"))@Can we get this directly from \code{d2} using a single\code{reshape()} call? We can, except that we will get a compositetime variable (which can be easily split if needed).<<>>=reshape(d2, direction = "long",v.names = "combined",varying = c("ht_before", "ht_after", "wt_before", "wt_after"),timevar = "when_what",times = c("pre_height", "post_height", "pre_weight", "post_weight"),idvar = "subject", ids = letters[1:n])@\section{Conversion from wide to long format}Conversion from long to wide format is generally simpler. Let ussimulate long format data from the same hypothetical setup.<<>>=d3 <- data.frame(sex = sample(c("M", "F"), 2 * n, rep = TRUE),ht = round(rnorm(2 * n, 165, 6), 1),wt = round(rnorm(2 * n, 80, 6)),subject = rep(1:n, 2),when = rep(c("pre", "post"), each = n))d3@To convert this to the wide format, the arguments \code{idvar} and\code{timevar} to \code{reshape()} are mandatory, and all othervariables are assumed to be time-varying. This is what we do in thenext example, where even \code{sex} is erroneously treated astime-varying.<<>>=reshape(d3, direction = "wide",idvar = "subject", timevar = "when")@To specify some variables as time-constant, the time-varying variablesmust be explicitly specified through \code{v.names}.<<eval=FALSE>>=reshape(d3, direction = "wide",idvar = "subject", timevar = "when",v.names = c("ht", "wt"))@This gives a warning because \code{sex} is not really time-constantin the dataset we have created. Let us fix that:<<>>=n <- 10d4 <- data.frame(sex = rep(sample(c("M", "F"), n, rep = TRUE), 2),ht = round(rnorm(2 * n, 165, 6), 1),wt = round(rnorm(2 * n, 80, 6)),subject = rep(1:n, 2),when = rep(c("pre", "post"), each = n))reshape(d4, direction = "wide",idvar = "subject", timevar = "when",v.names = c("ht", "wt"), sep = "_")@To specify the resulting wide format variable names explicitly insteadof using the automatically constructed defaults, we may use the\code{varying} argument as in wide-to-long conversion. As in thatcase, \code{varying} can be a vector of variable names, where the samecaveats apply regarding order.<<>>=reshape(d4, direction = "wide",idvar = "subject", timevar = "when",v.names = c("ht", "wt"),varying = c("h_before", "w_before", "h_after", "w_after"))@%% Pre 4.1.0: Error in varying[, i] : incorrect number of dimensionsFor more than one time-varying variable, it is safer to avoid thevector form and instead specify \code{varying} as a list or matrix.<<>>=reshape(d4, direction = "wide",idvar = "subject", timevar = "when",v.names = c("ht", "wt"),varying = list(c("h_before", "h_after"),c("w_before", "w_after")))@\end{document}