File: dplyr_extending.Rd

package info (click to toggle)
r-cran-dplyr 1.1.4-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,292 kB
  • sloc: cpp: 1,403; sh: 17; makefile: 7
file content (106 lines) | stat: -rw-r--r-- 5,420 bytes parent folder | download
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/generics.R
\name{dplyr_extending}
\alias{dplyr_extending}
\alias{dplyr_row_slice}
\alias{dplyr_col_modify}
\alias{dplyr_reconstruct}
\title{Extending dplyr with new data frame subclasses}
\usage{
dplyr_row_slice(data, i, ...)

dplyr_col_modify(data, cols)

dplyr_reconstruct(data, template)
}
\arguments{
\item{data}{A tibble. We use tibbles because they avoid some inconsistent
subset-assignment use cases.}

\item{i}{A numeric or logical vector that indexes the rows of \code{data}.}

\item{cols}{A named list used to modify columns. A \code{NULL} value should remove
an existing column.}

\item{template}{Template data frame to use for restoring attributes.}
}
\description{
\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}}

These three functions, along with \verb{names<-} and 1d numeric \code{[}
(i.e. \code{x[loc]}) methods, provide a minimal interface for extending dplyr
to work with new data frame subclasses. This means that for simple cases
you should only need to provide a couple of methods, rather than a method
for every dplyr verb.

These functions are a stop-gap measure until we figure out how to solve
the problem more generally, but it's likely that any code you write to
implement them will find a home in what comes next.
}
\section{Basic advice}{
This section gives you basic advice if you want to extend dplyr to work with
your custom data frame subclass, and you want the dplyr methods to behave
in basically the same way.
\itemize{
\item If you have data frame attributes that don't depend on the rows or columns
(and should unconditionally be preserved), you don't need to do anything.
The one exception to this is if your subclass extends a data.frame
directly rather than extending a tibble. The \verb{[.data.frame} method does not
preserve attributes, so you'll need to write a \code{[} method for your subclass
that preserves attributes important for your class.
\item If you have \strong{scalar} attributes that depend on \strong{rows}, implement a
\code{dplyr_reconstruct()} method. Your method should recompute the attribute
depending on rows now present.
\item If you have \strong{scalar} attributes that depend on \strong{columns}, implement a
\code{dplyr_reconstruct()} method and a 1d \code{[} method. For example, if your
class requires that certain columns be present, your method should return
a data.frame or tibble when those columns are removed.
\item If your attributes are \strong{vectorised} over \strong{rows}, implement a
\code{dplyr_row_slice()} method. This gives you access to \code{i} so you can
modify the row attribute accordingly. You'll also need to think carefully
about how to recompute the attribute in \code{dplyr_reconstruct()}, and
you will need to carefully verify the behaviour of each verb, and provide
additional methods as needed.
\item If your attributes that are \strong{vectorised} over \strong{columns}, implement
\code{dplyr_col_modify()}, 1d \code{[}, and \verb{names<-} methods. All of these methods
know which columns are being modified, so you can update the column
attribute according. You'll also need to think carefully about how to
recompute the attribute in \code{dplyr_reconstruct()}, and you will need to
carefully verify the behaviour of each verb, and provide additional
methods as needed.
}
}

\section{Current usage}{
\itemize{
\item \code{arrange()}, \code{filter()}, \code{slice()} (and the rest of the \verb{slice_*()}
family), \code{semi_join()}, and \code{anti_join()} work by generating a vector of
row indices, and then subsetting with \code{dplyr_row_slice()}.
\item \code{mutate()} generates a list of new column value (using \code{NULL} to indicate
when columns should be deleted), then passes that to \code{dplyr_col_modify()}.
It also uses 1d \code{[} to implement \code{.keep}, and will call \code{relocate()} if
either \code{.before} or \code{.after} are supplied.
\item \code{summarise()} and \code{reframe()} work similarly to \code{mutate()} but the data
modified by \code{dplyr_col_modify()} comes from \code{group_data()} or is built
from \code{.by}.
\item \code{select()} uses 1d \code{[} to select columns, then \verb{names<-} to rename them.
\code{rename()} just uses \verb{names<-}. \code{relocate()} just uses 1d \code{[}.
\item \code{inner_join()}, \code{left_join()}, \code{right_join()}, and \code{full_join()}
coerce \code{x} to a tibble, modify the rows, then use \code{dplyr_reconstruct()}
to convert back to the same type as \code{x}.
\item \code{nest_join()} converts both \code{x} and \code{y} to tibbles, modifies the rows,
and uses \code{dplyr_col_modify()} to handle modified key variables and the
list-column that \code{y} becomes. It also uses \code{dplyr_reconstruct()} to convert
the outer result back to the type of \code{x}, and to convert the nested tibbles
back to the type of \code{y}.
\item \code{distinct()} does a \code{mutate()} if any expressions are present, then
uses 1d \code{[} to select variables to keep, then \code{dplyr_row_slice()} to
select distinct rows.
}

Note that \code{group_by()} and \code{ungroup()} don't use any of these generics and
you'll need to provide methods for them directly, or rely on \code{.by} for
per-operation grouping.
}

\keyword{internal}