Create new data in a strictly row-wise fashion without vectorisation
Source:R/standalone-tidy-utils.R
rowwise_mutate.Rd
Applies an expression to each row and assignes it to a new column. Per-row failures are handled with default values (NAs) or can be intercepted by the user with a tryCatch(...) expression. There are many other ways to do a similar thing in `dplyr` and `purrr` but they are all more complicated than I expect them to be.
Arguments
- .data
a dataframe. grouping is ingnored
- ...
a named list of expressions similar to mutate but where the expressions to be evaluated are evaluated in only in the context of the current row - and are not vectorised. This does not support [dplyr::accross] syntax.
- .onerror
a function that is called for
Examples
# calculations are scoped only to current row. Hence max(x) == x always:
iris %>% rowwise_mutate(
widths = Sepal.Width+max(Petal.Width),
lengths = Sepal.Length+max(Petal.Length),
tmp = tibble::tibble(a=1, b=2)) %>%
dplyr::glimpse()
#> Rows: 150
#> Columns: 8
#> $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
#> $ Sepal.Width <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
#> $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
#> $ Petal.Width <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
#> $ Species <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
#> $ widths <dbl> 3.7, 3.2, 3.4, 3.3, 3.8, 4.3, 3.7, 3.6, 3.1, 3.2, 3.9, 3.…
#> $ lengths <dbl> 6.5, 6.3, 6.0, 6.1, 6.4, 7.1, 6.0, 6.5, 5.8, 6.4, 6.9, 6.…
#> $ tmp <list> [<tbl_df[1 x 2]>], [<tbl_df[1 x 2]>], [<tbl_df[1 x 2]>],…
# This is different to standard dplyr behaviour when the additional tibble
# column is considered. standard dplyr rowwise does something unexpected:
iris %>% dplyr::rowwise() %>% dplyr::mutate(
widths = Sepal.Width+max(Petal.Width),
lengths = Sepal.Length+max(Petal.Length),
tmp = tibble::tibble(a=1, b=2)) %>%
dplyr::glimpse()
#> Rows: 150
#> Columns: 8
#> Rowwise:
#> $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
#> $ Sepal.Width <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
#> $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
#> $ Petal.Width <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
#> $ Species <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
#> $ widths <dbl> 3.7, 3.2, 3.4, 3.3, 3.8, 4.3, 3.7, 3.6, 3.1, 3.2, 3.9, 3.…
#> $ lengths <dbl> 6.5, 6.3, 6.0, 6.1, 6.4, 7.1, 6.0, 6.5, 5.8, 6.4, 6.9, 6.…
#> $ tmp <tibble[,2]> <tbl_df[26 x 2]>
# As expressions are not vectorised we can use normal if ... else ... statements
# and errors can be handled and default values provided.
suppressWarnings(
iris %>% rowwise_mutate(
tmp = if (Petal.Width > 2.0) stop("error message: ",Petal.Width) else Petal.Width,
.onerror = function(e) -Petal.Width
) %>%
dplyr::glimpse()
)
#> Rows: 150
#> Columns: 6
#> $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
#> $ Sepal.Width <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
#> $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
#> $ Petal.Width <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
#> $ Species <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
#> $ tmp <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
# The default values
# are evaluated in the same context as the original expression, but only are
# defaults for all the columns so makes most sense when a default value is given
suppressWarnings(
iris %>% rowwise_mutate(
tmp = if (Petal.Width > 2.0) stop("too wide petals: ",Petal.Width) else Petal.Width,
tmp2 = if (Sepal.Width > 4) stop("too wide sepals: ",Sepal.Width) else Sepal.Width,
.onerror = function(e) Inf
) %>%
dplyr::glimpse()
)
#> Rows: 150
#> Columns: 7
#> $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
#> $ Sepal.Width <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
#> $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
#> $ Petal.Width <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
#> $ Species <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
#> $ tmp <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
#> $ tmp2 <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…