Создайте несколько столбцов в условиях и функциях ifelse, аргументы которых зависят от имени выходного столбца - PullRequest
1 голос
/ 19 марта 2020

Это мои данные:

# Test datasets
test_df <- data.frame(A =c(1, 2, 3, 3, 4), AKH_UL =c(111, 222, 333, 444, 555), AKH_LL = c(222, 333, 444, 555, 666),
                     AKH_UU = c(213, 242, 253, 546, 243), AKH_LU = c(453, 855, 784, 352, 585), FFL_UL =c(111, 222, 333, 444, 555), FFL_LL = c(222, 333, 444, 555, 666), FFL_UU = c(213, 242, 253, 546, 243), FFL_LU = c(453, 855, 784, 352, 585))

Я хочу создать два столбца, AKH и FFL. Значение столбца зависит от условий, и каждое условие связано с определенной функцией:

Simplified functions:

# Case 1: 
myfunction1 <- function(cost, cost_LL, cost_UL, cost_LU, cost_UU){

  test_df$cost <- cost_LL *cost_UL + cost_UU * cost_LU
}

# Case 2:
myfunction2 <-function(cost,cost_LL, cost_LU){
 test_df$cost <- cost_LL *cost_LU 
}

# Case 3: 
myfunction3 <-function(cost,cost_UL, cost_UU){
  test_df$cost <- costUL *costUU
}


Сейчас я делаю это в два отдельных этапа для каждого столбца. Например, для AKH:

test_df$AKH <-
  ifelse(test_df$A ==  1, 
      myfunction1(test_df$AKH, test_df$AKH_LL, test_df$AKH_UL, test_df$AKH_LU, test_df$AKH_UU),
        ifelse((test_df$A == 2, 
           myfunction2(test_df$AKH, test_df$AKH_LL, test_df$AKH_LU),
              ifelse((test_df$A == 3,
                 myfunction3(test_df$AKH, test_df$AKH_UL, test_df$AKH_UU),
                     99999))))

То же самое вычисление, которое я делаю для второго члена, только с FFL вместо AKH внутри формул.

Это выглядит довольно ужасно (в rl это не только два, но и 10 столбцов), и я боюсь, что другие дети будут смеяться надо мной, когда увидят мой сценарий.

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

Ответы [ 2 ]

2 голосов
/ 19 марта 2020

Замените test_df$AKH на test_df[,column_names[i]] и используйте функции for и paste.

Пример:

column_names <- c("AKH", "FFL")

for(i in 1:length(column_names){

test_df[,column_names[i]]<-
 ifelse(test_df$A ==  1, 
     myfunction1(test_df[,column_names[i]]
                 test_df[,paste(column_names[i],"LL",sep = "_")], 
                 test_df[,paste(column_names[i],"UL",sep = "_")], 
                 test_df[,paste(column_names[i],"LU",sep = "_")], 
                 test_df[,paste(column_names[i],"UU",sep = "_")]),
      ifelse((test_df$A == 2, 
          myfunction2(test_df[,column_names[i]], 
                      test_df[,paste(column_names[i],"LL",sep = "_")],
                      test_df[,paste(column_names[i],"LU",sep = "_")]),
             ifelse((test_df$A == 3,
                myfunction3(test_df[,column_names[i]],
                            test_df$[,paste(column_names[i],"UL",sep = "_")], 
                            test_df$[,paste(column_names[i],"UU",sep = "_")]),
                            99999))))

}

1 голос
/ 19 марта 2020

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

# Case 1: 
myfunction1 <- function(cost_LL, cost_UL, cost_LU, cost_UU) {
  cost_LL * cost_UL + cost_UU * cost_LU
}

# Case 2:
myfunction2 <- function(cost_LL, cost_LU) {
  cost_LL * cost_LU 
}

# Case 3: 
myfunction3 <-function(cost_UL, cost_UU) {
  cost_UL * cost_UU
}

Я также исправил несоответствия имен.

Чтобы рассчитать затраты на основе переменной «A», я изменил форму фрейма данных, используя пакет tidyr , чтобы у вас было только пять столбцов, столбец «A» и четыре » столбцы стоимости, которые используются в ваших функциях (UL, LL, UU и LU). Таким образом, вы можете иметь столько наборов переменных, сколько захотите. Затем, используя mapply, я создаю столбец затрат.

library(tidyr)
library(dplyr)

test_df %>%
  pivot_longer(cols=-A, names_to=c("ID", ".value"),
               names_pattern="(.+)_([U|L][L|U])") %>% # Run to here to see the result
  group_by(A, ID) %>%
  transmute(cost=ifelse(A==1, mapply(myfunction1, LL, UL, LU, UU),
                     ifelse(A==2, mapply(myfunction2, LL, LU),
                            ifelse(A==3, mapply(myfunction3, UL, UU), NA))))

# A tibble: 10 x 3
# Groups:   A, ID [8]
       A ID      cost
   <dbl> <chr>  <dbl>
 1     1 AKH   121131
 2     1 FFL   121131
 3     2 AKH   284715
 4     2 FFL   284715
 5     3 AKH    84249
 6     3 FFL    84249
 7     3 AKH   242424
 8     3 FFL   242424
 9     4 AKH       NA
10     4 FFL       NA

Это должно работать на любом количестве наборов переменных.


Редактировать : Чтобы получить затраты в широком формате, нам нужно сначала добавить переменную id из-за дубликатов в столбце «A». Все остальное аналогично приведенному выше, за исключением того, что последняя строка переводит результат в широкую форму для каждой переменной.

test_df %>%
  group_by(A) %>%
  mutate(id=row_number()) %>%
  pivot_longer(cols=-c(A,id), names_to=c("ID", ".value"),
               names_pattern="(.+)_([U|L][L|U])") %>% # Run to here to see the result
  group_by(A, id, ID) %>%
  transmute(cost=ifelse(A==1, mapply(myfunction1, LL, UL, LU, UU),
                        ifelse(A==2, mapply(myfunction2, LL, LU),
                               ifelse(A==3, mapply(myfunction3, UL, UU), NA)))) %>%
  pivot_wider(id_cols=c(A, id), names_from=ID, values_from = cost)

# A tibble: 5 x 4
# Groups:   A, id [5]
      A    id    AKH    FFL
  <dbl> <int>  <dbl>  <dbl>
1     1     1 121131 121131
2     2     1 284715 284715
3     3     1  84249  84249
4     3     2 242424 242424
5     4     1     NA     NA
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...