Добавление функций в конвейер на основе аргумента

Я пытаюсь написать функцию, которая несколько раз вызывает другую функцию в своем теле. Я надеюсь контролировать количество таких вызовов функций и их соответствующую цель с помощью аргумента, но это становится сложным из-за структуры конвейеров. Представьте себе этот простой пример изменяющихся столбцов. Я полностью осознаю, что это не лучший пример, поскольку вы не стали бы вызывать mutate несколько раз для разных целей, но потерпите меня. Это всего лишь резервный пример, поэтому важно, чтобы каждый вызов mutate соответствовал строке, передаваемой через аргумент cols.

library(dplyr)

scale_cols <- function(data, cols = c("mpg", "cyl")) {
  
  processed_data <- data |> 
    mutate("mpg" = scale(mpg)) |> 
    mutate("cyl" = scale(cyl))
  
  return(processed_data)
}

scale_cols(mtcars)
#>                             mpg        cyl  disp  hp drat    wt  qsec vs am
#> Mazda RX4            0.15088482 -0.1049878 160.0 110 3.90 2.620 16.46  0  1
#> Mazda RX4 Wag        0.15088482 -0.1049878 160.0 110 3.90 2.875 17.02  0  1
#> Datsun 710           0.44954345 -1.2248578 108.0  93 3.85 2.320 18.61  1  1
#> Hornet 4 Drive       0.21725341 -0.1049878 258.0 110 3.08 3.215 19.44  1  0
#> Hornet Sportabout   -0.23073453  1.0148821 360.0 175 3.15 3.440 17.02  0  0
#> Valiant             -0.33028740 -0.1049878 225.0 105 2.76 3.460 20.22  1  0
#> Duster 360          -0.96078893  1.0148821 360.0 245 3.21 3.570 15.84  0  0
#> Merc 240D            0.71501778 -1.2248578 146.7  62 3.69 3.190 20.00  1  0
#> Merc 230             0.44954345 -1.2248578 140.8  95 3.92 3.150 22.90  1  0

Created on 2022-11-28 with reprex v2.0.2

В настоящее время, какие столбцы должны быть преобразованы, жестко запрограммировано, но я бы предпочел иметь возможность выбирать столбцы для преобразования с помощью аргумента cols. Можно ли сопоставить или применить функцию mutate к элементам cols, чтобы в итоге был создан полностью функциональный конвейер? Спасибо за ваше время.

Используйте across(). data |> mutate(across(all_of(cols), scale)). См. описание и другие примеры на странице справки ?across.

Gregor Thomas 28.11.2022 16:52

Это не то, что я ищу. Важно, чтобы для каждого элемента аргумента в конвейер добавлялся еще один вызов функции. Это просто пример, а не реальная проблема, которую я пытаюсь решить.

O René 28.11.2022 16:54

Тогда было бы полезно создать пример, который ближе к проблеме, которую вы на самом деле пытаетесь решить. Функция across() распознает любой из вариантов аккуратного выбора для выбора столбцов. Непонятно, почему это не сработает.

MrFlick 28.11.2022 16:58

ну, я пытаюсь добавить подогнанные модели в стек, основываясь на аргументе, но это огромная проблема для любого, кто настроит его локально, поскольку он включает в себя сначала подгонку нескольких моделей. Это простой способ описать проблему. Мне нужно контролировать вызовы функций в аргументе, и я подозреваю, что есть способ решить эту проблему итеративно, применяя или отображая предоставленные аргументы.

O René 28.11.2022 17:00

Это обязательно должна быть труба? Почему бы не зациклиться на столбцах и не выполнить простое присваивание, например data[[col]] = scale(data[[col]])?

Spacedman 28.11.2022 17:05

OP изначально отвергает комментарии о том, что «есть лучшие способы сделать это», настаивает на том, что требуется конвейерное решение и что их представление проблемы однозначно лучшее. Затем они принимают ответ, который не передается по конвейеру. Я нахожу это совершенно непоследовательным.

Limey 28.11.2022 17:21

Приношу свои извинения за некорректно заданный вопрос и возникшие в связи с этим проблемы. Все, что я намеревался сделать, это упростить для людей, которые заинтересованы, достигнув полной противоположности. Спасибо за помощь, но она оказалась очень полезной.

O René 28.11.2022 17:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я согласен с @GregorThomas в том, что across является очевидным решением вашего вопроса в том виде, в котором он опубликован, и с @MrFlick в том, что вам следует изменить свой пост, чтобы прояснить свои намерения. Тем не менее, и основываясь на ваших комментариях, я считаю, что это дает вам то, что вы хотите (и больше соответствует стилю tidyverse, чем ваш пример).

scale_cols <- function(data, cols) {
  for (c in cols) {
    data <- data %>% mutate({{c}} := scale({{c}}))
  }
  data
}

mtcars %>% scale_cols(vars(mpg, cyl))
                            mpg        cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4            0.15088482 -0.1049878 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag        0.15088482 -0.1049878 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710           0.44954345 -1.2248578 108.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive       0.21725341 -0.1049878 258.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout   -0.23073453  1.0148821 360.0 175 3.15 3.440 17.02  0  0    3    2
Valiant             -0.33028740 -0.1049878 225.0 105 2.76 3.460 20.22  1  0    3    1
<output truncated for brevity>

Это то, что я искал, спасибо за ваш комментарий. Я понимаю, что пример был плохим, поскольку есть гораздо более простые решения для опубликованного кода, но это был самый простой способ воспроизвести мою локальную проблему с минимальными усилиями по написанию кода для людей, которые пытаются помочь.

O René 28.11.2022 17:09
Ответ принят как подходящий

Для меня это звучит так, как будто вы хотите итеративно применить функцию один раз для каждого элемента переданного вектора и чтобы результат включал изменения кумулятивно. Нестандартная оценка, связанная с mutate, а также наличие более эффективных способов выполнения этой конкретной операции, вероятно, делает его неоптимальным примером.

Однако основная концепция того, что вы пытаетесь сделать, выполняется базовой функцией R Reduce, которая принимает начальный аргумент (например, фрейм входных данных) и итеративно применяет функцию двух переменных (выход последней итерации). и следующий член вектора cols)

scale_cols <- function(data, cols = c("mpg", "cyl")) {
  
  Reduce(function(x, y) { 
    x[[y]] <- scale(x[[y]]) 
    return(x)
    }, x = cols, init = data)
}

В результате чего:

scale_cols(mtcars)
#>                             mpg        cyl  disp  hp drat    wt  qsec vs am
#> Mazda RX4            0.15088482 -0.1049878 160.0 110 3.90 2.620 16.46  0  1
#> Mazda RX4 Wag        0.15088482 -0.1049878 160.0 110 3.90 2.875 17.02  0  1
#> Datsun 710           0.44954345 -1.2248578 108.0  93 3.85 2.320 18.61  1  1
#> Hornet 4 Drive       0.21725341 -0.1049878 258.0 110 3.08 3.215 19.44  1  0
#> Hornet Sportabout   -0.23073453  1.0148821 360.0 175 3.15 3.440 17.02  0  0
#> Valiant             -0.33028740 -0.1049878 225.0 105 2.76 3.460 20.22  1  0
#> Duster 360          -0.96078893  1.0148821 360.0 245 3.21 3.570 15.84  0  0
#> Merc 240D            0.71501778 -1.2248578 146.7  62 3.69 3.190 20.00  1  0
#> Merc 230             0.44954345 -1.2248578 140.8  95 3.92 3.150 22.90  1  0
#> Merc 280            -0.14777380 -0.1049878 167.6 123 3.92 3.440 18.30  1  0
#> Merc 280C           -0.38006384 -0.1049878 167.6 123 3.92 3.440 18.90  1  0
#> Merc 450SE          -0.61235388  1.0148821 275.8 180 3.07 4.070 17.40  0  0
#> Merc 450SL          -0.46302456  1.0148821 275.8 180 3.07 3.730 17.60  0  0
#> Merc 450SLC         -0.81145962  1.0148821 275.8 180 3.07 3.780 18.00  0  0
#> Cadillac Fleetwood  -1.60788262  1.0148821 472.0 205 2.93 5.250 17.98  0  0
#> Lincoln Continental -1.60788262  1.0148821 460.0 215 3.00 5.424 17.82  0  0
#> Chrysler Imperial   -0.89442035  1.0148821 440.0 230 3.23 5.345 17.42  0  0
#> Fiat 128             2.04238943 -1.2248578  78.7  66 4.08 2.200 19.47  1  1
#> Honda Civic          1.71054652 -1.2248578  75.7  52 4.93 1.615 18.52  1  1
#> Toyota Corolla       2.29127162 -1.2248578  71.1  65 4.22 1.835 19.90  1  1
#> Toyota Corona        0.23384555 -1.2248578 120.1  97 3.70 2.465 20.01  1  0
#> Dodge Challenger    -0.76168319  1.0148821 318.0 150 2.76 3.520 16.87  0  0
#> AMC Javelin         -0.81145962  1.0148821 304.0 150 3.15 3.435 17.30  0  0
#> Camaro Z28          -1.12671039  1.0148821 350.0 245 3.73 3.840 15.41  0  0
#> Pontiac Firebird    -0.14777380  1.0148821 400.0 175 3.08 3.845 17.05  0  0
#> Fiat X1-9            1.19619000 -1.2248578  79.0  66 4.08 1.935 18.90  1  1
#> Porsche 914-2        0.98049211 -1.2248578 120.3  91 4.43 2.140 16.70  0  1
#> Lotus Europa         1.71054652 -1.2248578  95.1 113 3.77 1.513 16.90  1  1
#> Ford Pantera L      -0.71190675  1.0148821 351.0 264 4.22 3.170 14.50  0  1
#> Ferrari Dino        -0.06481307 -0.1049878 145.0 175 3.62 2.770 15.50  0  1
#> Maserati Bora       -0.84464392  1.0148821 301.0 335 3.54 3.570 14.60  0  1
#> Volvo 142E           0.21725341 -1.2248578 121.0 109 4.11 2.780 18.60  1  1
#>                     gear carb
#> Mazda RX4              4    4
#> Mazda RX4 Wag          4    4
#> Datsun 710             4    1
#> Hornet 4 Drive         3    1
#> Hornet Sportabout      3    2
#> Valiant                3    1
#> Duster 360             3    4
#> Merc 240D              4    2
#> Merc 230               4    2
#> Merc 280               4    4
#> Merc 280C              4    4
#> Merc 450SE             3    3
#> Merc 450SL             3    3
#> Merc 450SLC            3    3
#> Cadillac Fleetwood     3    4
#> Lincoln Continental    3    4
#> Chrysler Imperial      3    4
#> Fiat 128               4    1
#> Honda Civic            4    2
#> Toyota Corolla         4    1
#> Toyota Corona          3    1
#> Dodge Challenger       3    2
#> AMC Javelin            3    2
#> Camaro Z28             3    4
#> Pontiac Firebird       3    2
#> Fiat X1-9              4    1
#> Porsche 914-2          5    2
#> Lotus Europa           5    2
#> Ford Pantera L         5    4
#> Ferrari Dino           5    6
#> Maserati Bora          5    8
#> Volvo 142E             4    2

Created on 2022-11-28 with reprex v2.0.2

Я полностью согласен с критикой моего опубликованного примера, я должен был больше подумать об этом. Я стремился сократить необходимые усилия по кодированию для людей, которые в этом заинтересованы, но вы кратко разобрали проблему и не ссылались на воображаемые ограничения. Спасибо за ваш ответ.

O René 28.11.2022 17:18

Другие вопросы по теме