Как я могу сопоставить функцию для применения только к определенным строкам во фрейме данных? - PullRequest
1 голос
/ 01 ноября 2019

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

Так, например, скажем, у меня есть эта настройка:

library(tidyverse)

add_one <- function(vector, x_id){
  return(vector[x_id] + 1)
}

test <- data.frame(x = c(1,2,3,4), y = c(1,2,3,4), run_on = c(TRUE,FALSE,TRUE,FALSE))
test

Таким образом, фрейм тестовых данных выглядит следующим образом:

>  x y run_on
>1 1 1   TRUE
>2 2 2  FALSE
>3 3 3   TRUE
>4 4 4  FALSE

Итак, я хочу перебрать фрейм данных и установить в столбце y результат применения функции add_one () к столбцу x только для строк, где run_on равен TRUE. Я хочу, чтобы конечный результат выглядел так:

>  x y run_on
>1 1 2   TRUE
>2 2 2  FALSE
>3 3 4   TRUE
>4 4 4  FALSE

Я смог перебрать функцию по всем строкам, используя apply (). Так, например:

test$y <- apply(test,1,add_one,x_id = 1)
test

>  x y run_on
>1 1 2   TRUE
>2 2 3  FALSE
>3 3 4   TRUE
>4 4 5  FALSE

Но это также применяет функцию к строкам 2 и 4, что мне не нужно. Я подозреваю, что может быть какой-то способ сделать это, используя версии функций map () из :: purrr, поэтому я отметил этот пост как таковой.

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

ОБНОВЛЕНИЕ

Мне удалось найти решение. Некоторые из предложенных здесь решений работали в моем игрушечном примере, но не распространялись на более сложную функцию, которую я фактически использовал. В конечном итоге то, что сработало, было похоже на то, что предложил tmfmnk. Я просто обернул исходную функцию внутри другой функции, которая включала оператор if, чтобы определить, применять ли исходную функцию или нет. Итак, чтобы расширить мой пример с игрушкой, мое решение выглядит следующим образом:

add_one_if <- function(vector, x_id, y_id, run_on_id){
    if(vector[run_on_id]){
        return(add_one(vector,x_id))}
    else{
        return(vector[x_id])
    }
}

test$y <- apply(test, 1, add_one_if, x_id = 1, y_id = 2, run_on_id = 3)

Это кажется немного запутанным, но оно работает для меня и воспроизводимо и надежно так, как мне нужно.

Ответы [ 3 ]

2 голосов
/ 01 ноября 2019

Вы также можете сделать:

add_one <- function(data, vector, x_id, n, is.true = c(TRUE, FALSE)) {  
 if (is.true) {
  return(data[[vector]] + (data[[x_id]]) * n)
 } else {
  return(data[[vector]] + (!data[[x_id]]) * n)
 }
}   

add_one(test, vector = "y", x_id = "run_on", 1, is.true = TRUE)

[1] 2 2 4 4

add_one(test, vector = "y", x_id = "run_on", 5, is.true = FALSE)

[1] 1 7 3 9
2 голосов
/ 01 ноября 2019

Может быть, ваш реальный случай сложнее, чем это разрешено, но почему бы просто не использовать ifelse?

test$y <- ifelse(test$run_on,add_one(test,x),y)

Или даже:

test$y[test$run_on]<-add_one(test[run_on,],x)
1 голос
/ 01 ноября 2019

Вам не нужно будет использовать purrr, пока вы не примените одну и ту же функцию к нескольким столбцам. Поскольку вы хотите изменить только один столбец, но в зависимости от условия вы можете использовать mutate() + case_when().

mutate(test, y = case_when(run_on ~ add_one(y),
                           !run_on ~ y))
#>   x y run_on
#> 1 1 2   TRUE
#> 2 2 2  FALSE
#> 3 3 4   TRUE
#> 4 4 4  FALSE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...