Оптимизация вычислений в функции dplyr mutate

#r #optimization #dplyr

#r #оптимизация #dplyr

Вопрос:

Предположим, что следующая таблица:

 library(dplyr)
library(tibble)
library(purrr)

df = tibble(
  client = c(1,1,1,1,2,2,2,2),
  prod_type = c(1,1,2,2,1,1,2,2),
  max_prod_type = c(2,2,2,2,2,2,2,2),
  value_1 = c(10,20,30,30,100,200,300,300),
  value_2 = c(1,2,3,3,1,2,3,3),
)
# A tibble: 8 x 5
  client prod_type max_prod_type value_1 value_2
   <dbl>     <dbl>         <dbl>   <dbl>   <dbl>
1      1         1             2      10       1
2      1         1             2      20       2
3      1         2             2      30       3
4      1         2             2      30       3
5      2         1             2     100       1
6      2         1             2     200       2
7      2         2             2     300       3
8      2         2             2     300       3
 

Столбец ‘max_prod_type’ здесь обозначает максимальное значение для столбца ‘prod_type’ для каждого значения ‘client’. Мне нужно вычислить новый столбец ‘sum’, который будет содержать сумму от добавления значений из ‘value_1’ и ‘value_2’, но только для тех строк, где ‘prod_type’ == ‘max_prod_type’ для каждого значения ‘client’.

Я попробовал следующий код:

 df %>%
  mutate(
    sum = 
      map2_dbl(
        client, max_prod_type,
        ~case_when(
          prod_type == .y~
            filter(df, client == .x, prod_type == .y) %>%
            mutate(sum = value_1   value_2) %>%
            select(sum) %>%
            sum(),
          T~NA_real_
        )
      )
  )
 

Желаемый результат следующий:

  # A tibble: 8 x 6
  client prod_type max_prod_type value_1 value_2   sum
   <dbl>     <dbl>         <dbl>   <dbl>   <dbl> <dbl>
1      1         1             2      10       1    NA
2      1         1             2      20       2    NA
3      1         2             2      30       3    66
4      1         2             2      30       3    66
5      2         1             2     100       1   NA
6      2         1             2     200       2   NA
7      2         2             2     300       3   606
8      2         2             2     300       3   606
 

Но это выдает ошибку:

 Error: Problem with `mutate()` input `sum`.
x Result 1 must be a single double, not a double vector of length 6
i Input `sum` is `map2_dbl(...)`.
 

Более того, как по мне, такой способ реализации несколько медленный. Мне интересно, есть ли какое-либо правильное и более оптимизированное решение этой проблемы.

Ценю вашу помощь!

Ответ №1:

Одним из вариантов может быть:

 df %>%
 group_by(client) %>%
 mutate(res = row_number() == which(value_1 == max(value_1)),
        res = if_else(res, sum(value_1[res])   sum(value_2[res]), NA_real_))

  client prod_type max_prod_type value_1 value_2   res
   <dbl>     <dbl>         <dbl>   <dbl>   <dbl> <dbl>
1      1         1             2      10       1    NA
2      1         1             2      20       2    NA
3      1         2             2      30       3    66
4      1         2             2      30       3    66
5      2         1             2     100       1    NA
6      2         1             2     200       2    NA
7      2         2             2     300       3   606
8      2         2             2     300       3   606
 

Ответ №2:

Я думаю, что это ближе к тому, что вы хотите:

 df %>%
  mutate(sum = case_when(prod_type == max_prod_type ~ value_1   value_2,
                         TRUE ~ NA_real_))

# A tibble: 6 x 6
  client prod_type max_prod_type value_1 value_2   sum
   <dbl>     <dbl>         <dbl>   <dbl>   <dbl> <dbl>
1      1         1             2      10       1    NA
2      1         1             2      20       2    NA
3      1         2             2      30       3    33
4      2         1             2     100       1    NA
5      2         1             2     200       2    NA
6      2         2             2     300       3   303
 

Комментарии:

1. Прошу прощения за то, что пропустил информацию, приведенную в первой версии вопроса. Я внес в нее некоторые изменения. На самом деле, если у клиента есть 2 строки с максимальным типом продукта, нам нужно обработать желаемое вычисление для двух строк, пожалуйста, смотрите Мое обновление