deschen
deschen

Reputation: 10996

tidyverse divide several columns by other columns n positions later (avoiding loops)

library(tidyverse)
dat <- tribble(
  ~Scenario,     ~V1,    ~V2,    ~V3,    ~V4,
  1,    0.97,   0.46,   0.79,   0.25,
  1,    0.21,   0.45,   0.23,   0.63,
  1,    0.95,   0.97,   0.07,   0.61,
  1,    0.93,   0.79,   0.23,   0.86,
  2,    0.22,   0.01,   0.42,   0.47,
  2,    0.71,   0.17,   0.16,   0.88,
  3,    0.73,   0.38,   0.10,   0.77,
  3,    0.49,   0.37,   0.90,   0.52,
  3,    0.99,   0.71,   0.66,   0.05,
  3,    0.72,   0.75,   0.69,   0.01,
  3,    0.15,   0.87,   0.12,   0.02,
  4,    0.94,   0.30,   0.91,   0.99)

I'm adding four new columns to this data, where each new column represents the sum of each V1:V4 column grouped by Scenario:

dat_new <- dat %>%
  group_by(Scenario) %>%
  mutate_at(vars(-group_cols()), .funs = list(sum = sum))

I'm looking for a simple way to divide V1 by V1_sum, V2 by V2_sum and so on assuming that a) I have as many original v columns as I have sum columns and b) that the data is correctly ordered and following my pattern where I first have all my v columns followed by the sum columns.

I just asked a another question here on SO where the focus was on pivoting the data to long format and then transform it back to wide format, but I was wondering if there was an easier solution in the tidyverse.

Note: I could probably just loop through each column and divide it by the column 4 positions later, but I was looking for a more elegant solution.

Upvotes: 1

Views: 126

Answers (1)

akrun
akrun

Reputation: 887391

We can expand the function inside list instead of creating temporary sum columns and then divide

library(dplyr)
dat %>% 
   group_by(Scenario) %>% 
   mutate_at(vars(-group_cols()), .funs = list(percentage =  ~ ./sum(.)))

If it is from dat_new, one option is map

library(purrr)
map2_dfc(dat %>% 
             select(V1:V4), 
        dat_new %>% 
             ungroup %>%
             select(ends_with('sum')), `/`)

Or using base R

dat[2:5]/dat_new[6:9]

Upvotes: 2

Related Questions