Подмножество в определенной пользователем функции для назначения значений целевому столбцу - PullRequest
0 голосов
/ 03 января 2019

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

data <-data.frame("exists" = c(1,0,1,0,1,0,0,0,1,1), 
                  "specific" = c("yes", NA, "no", NA, NA, NA, NA, NA, NA, "no"), 
                  "general" = c(NA, "yes", NA, "yes", "yes", NA, "no", NA, "no", NA), 
                  "therefore" = 0) 

Целевой столбец - therefore со значением по умолчанию 0. Я могу вручную присвоить значения therefore с тремя строками подмножества (или вложенными ifelse операторами, но я видел предложения, которых следует избегать ifelse для присвоения значений).

data[data["exists"] == 0, "therefore"] <- NA

data[grepl("yes", data[["specific"]], ignore.case=T), "therefore"] <- 1       

data[data["exists"] == 1 & grepl("yes", data[["general"]], ignore.case=T), 
"therefore"] <- 1

Это дает правильный вывод:

> data["therefore"]
   therefore
1          1
2         NA
3          0
4         NA
5          1
6         NA
7         NA
8         NA
9          0
10         0

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

fun <- function (doesitapply, string, speccol, gencol, target) {   

  data[data[doesitapply] == 0, target] <- NA

  data[grepl(string, data[[speccol]], ignore.case=T), target] <- 1

  data[data[doesitapply] == 1 & grepl(string, data[[gencol]], 
  ignore.case=T), target] <- 1    

}

Когда я использую свою новую функцию fun(), ошибка не выдается, но therefore кажется неизменной по сравнению со значением по умолчанию.

fun(doesitapply = "exists", string = "yes", speccol = "specific", gencol = 
"general", target = "therefore")

> data["therefore"]
   therefore
1          0
2          0
3          0
4          0
5          0
6          0
7          0
8          0
9          0
10         0

Это как-то связано с подмножеством имен столбцов в определенной пользователем функции? Я пытался использовать [[]] вместо [] для всех случаев поднабора в функции, но ...

 Error in `[[<-.data.frame`(`*tmp*`, data[[doesitapply]] == 0, target,  : 
  only a single element should be replaced 

Я посмотрел этот пост , но мне трудно применить его ответы к моему делу. Руководство или предложения приветствуются!

1 Ответ

0 голосов
/ 03 января 2019

Когда код в вашей функции запускается вне функции (после установки всех переменных, которые вы использовали), он работает так, как вы ожидали:

doesitapply <- "exists"
string <- "yes"
speccol <- "specific"
gencol <- "general"
target <- "therefore"

data[data[doesitapply] == 0, target] <- NA
data[grepl(string, data[[speccol]], ignore.case=T), target] <- 1
data[data[doesitapply] == 1 & grepl(string, data[[gencol]], ignore.case=T), target] <- 1 

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

Вы можете изменить свою функцию, чтобы изменить <- на <<- во всех 3 строках. Оператор <- всегда назначает в локальной области, тогда как оператор <<- ищет родительскую среду в поисках существующей переменной с этим именем.

Вместо назначения более 3 операторов может быть более типичным использование ifelse, которое здесь будет приемлемо, или, возможно, функция case_when из dplyr https://www.rdocumentation.org/packages/dplyr/versions/0.7.8/topics/case_when, которая устраняет необходимость использования вложенности .

Также возможно упростить тесты (например, избегать grepl) в зависимости от ожидаемых значений.

...