# Arithmetic on nested dataframes

Hi all. I have a dataset where I would like to calculate cumulative sums, moving averages etc

Using iris I can nest by species

``````nested <- iris %>%
group_by(Species) %>%
nest()
``````

And then

``````nested %>%
mutate(cumulative = map(data, cumsum)) %>%
unnest()
``````

Which gives me a df with all the cumulative values at the end. Perfect

A tibble: 150 x 9
Groups: Species [3]
Species Sepal.Length Sepal.Width Petal.Length Petal.Width Sepal.Length1

1 setosa 5.1 3.5 1.4 0.2 5.1
2 setosa 4.9 3 1.4 0.2 10
3 setosa 4.7 3.2 1.3 0.2 14.7
4 setosa 4.6 3.1 1.5 0.2 19.3
5 setosa 5 3.6 1.4 0.2 24.3
6 setosa 5.4 3.9 1.7 0.4 29.7
7 setosa 4.6 3.4 1.4 0.3 34.3
8 setosa 5 3.4 1.5 0.2 39.3
9 setosa 4.4 2.9 1.4 0.2 43.7
10 setosa 4.9 3.1 1.5 0.1 48.6
... with 140 more rows, and 3 more variables: Sepal.Width1 ,
Petal.Length1 , Petal.Width1

I wanted to use movavg from the pracma package (with moving average of 6) on iris and have used the following and variations of the code with no luck. For example the below gives: Error in movavg(x = data, n = 6) : is.numeric(x) is not TRUE

``````nested %>%
mutate(movingaverage = map(data, movavg(n = 6))) %>%
unnest()
``````

New to R and purrr in particular so any help would be much appreciated

@Nilafhiosagam Your approach seems needlessly complicated. You don't need `nest` to achieve the desired result.

``````library(dplyr)

iris %>%
group_by(Species) %>%
mutate_all(.funs = cumsum)

# A tibble: 150 x 5
# Groups:   Species [3]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl>       <dbl>        <dbl>       <dbl> <fct>
1          5.1         3.5          1.4         0.2 setosa
2         10           6.5          2.8         0.4 setosa
3         14.7         9.7          4.1         0.6 setosa
4         19.3        12.8          5.6         0.8 setosa
5         24.3        16.4          7           1   setosa
6         29.7        20.3          8.7         1.4 setosa
``````

The same approach can be used with other functions. I haven't used the `pracma` library but here's how to calculate rolling means using `zoo`.

``````library(zoo)

iris %>%
group_by(Species) %>%
mutate_all(.funs = rollmean, k = 6, fill = NA)

# A tibble: 150 x 5
# Groups:   Species [3]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl>       <dbl>        <dbl>       <dbl> <fct>
1        NA          NA           NA         NA     setosa
2        NA          NA           NA         NA     setosa
3         4.95        3.38         1.45       0.233 setosa
4         4.87        3.37         1.45       0.25  setosa
5         4.88        3.43         1.47       0.25  setosa
6         4.83        3.38         1.48       0.25  setosa
``````

`k` defines the width of the rolling window as you'd expect. The `fill` parameter is required to ensure that the output contains the same number of rows as the input. You can change the fill value to suit your requirement.

Note: By default `rollmean` uses a center-aligned window. As a result, you will find rows of NA values at the top and bottom of the output data frame. If you'd rather have the NAs at the beginning instead, you can pass the `align` parameter like so:

``````iris %>%
group_by(Species) %>%
mutate_all(.funs = rollmean, k = 6, fill = NA, align = "right")

# A tibble: 150 x 5
# Groups:   Species [3]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl>       <dbl>        <dbl>       <dbl> <fct>
1        NA          NA           NA         NA     setosa
2        NA          NA           NA         NA     setosa
3        NA          NA           NA         NA     setosa
4        NA          NA           NA         NA     setosa
5        NA          NA           NA         NA     setosa
6         4.95        3.38         1.45       0.233 setosa
``````
3 Likes

thank you very much, this is a much more straightforward approach

@Nilafhiosagam Good to hear! If I've answered your question, would you mind marking my post as a solution?

1 Like

Ah of course, thanks again

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.