2015-12-22 2 views
1

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

Вот простой кадр данных df всех перестановки 3 переменных:

#> dput(df) 
structure(list(var1 = structure(c(1L, 1L, 2L, 2L, 3L, 3L), .Label = c("a", 
"b", "c"), class = "factor"), var2 = structure(c(2L, 3L, 1L, 
3L, 1L, 2L), .Label = c("a", "b", "c"), class = "factor"), var3 =  structure(c(3L, 
2L, 3L, 1L, 2L, 1L), .Label = c("a", "b", "c"), class = "factor"), 
    X1 = c(0.5, 0.5, 0.8, 0.8, 0.3, 0.3), X2 = c(0.8, 0.3, 0.5, 
    0.3, 0.5, 0.8), X3 = c(0.3, 0.8, 0.3, 0.5, 0.8, 0.5)), .Names = c("var1", 
"var2", "var3", "X1", "X2", "X3"), row.names = c(NA, -6L), class = "data.frame") 

Моя цель состоит в том, чтобы добраться до среднего самостоятельного значения порядка каждый переменный. Чтобы добраться туда, мне нужно создать две промежуточные переменные: одну умножить m1, m2, m3, m4 и одну вычесть s1, s2, s3, s4. Переменные m1 и s1 являются специальными, m1 = X1 и s1 = X1-1. Тем не менее, другие должны обратиться к предыдущему: m2 = X2*X1 и s2 = m2-m1.

Я попытался объединить идеи из этого вопроса SO: R - dplyr - mutate - use dynamic variable names с lazyeval interp, чтобы я мог динамически ссылаться на другие переменные, а также динамически назвать мутированные столбцы. Тем не менее, он оставил только последний отправленный, и переименование не сработало, поэтому я получил один дополнительный столбец, названный, например, X2*X3, что хорошо в этом примере с 3. Когда у меня было 5, он дал один дополнительная колонка X4*X5.

for(n in 2:n_params) { 
    varname <- paste("m", n, sep=".") 
    df <- mutate_(df, .dots = setNames(interp(~one*two, one=as.name(paste0("X",n-1)), 
               two=as.name(paste0("X",n))),varname)) 
    df 
    } 

Так как я не могу понять, почему это не работает, я создал серию, если заявления, вычислить m с и s с.

xx <- data.frame(df) %>% 
    mutate(m1 = X1, 
      s1 = X1 - 1) 
    if(n_params >= 2) { 
    xx <- data.frame(xx) %>% 
     mutate(m2 = m1 * X2, 
       s2 = m2 - m1) 
    } 
    if(n_params >= 3) { 
    xx <- data.frame(xx) %>% 
     mutate(m3 = m2 * X3, 
       s3 = m3 - m2) 
    } 
    if(n_params >= 4) { 
    xx <- data.frame(xx) %>% 
     mutate(m4 = m3 * X4, 
       s4 = m4 - m3) 
    } 
    if(n_params >= 5) { 
    xx <- data.frame(xx) %>% 
     mutate(m5 = m4 * X5, 
     s5 = m5 - m4) 
    } 
    if(n_params >= 6) { 
    xx <- data.frame(xx) %>% 
     mutate(m6 = m5 * X6, 
       s6 = m6 - m5) 
    } 

Похоже, что я должен быть в состоянии написать функцию, которая создает это,

В псевдокоде:

function(n_params) { 
function(x) { 
    new_df <- df %>% 
      mutate(m1 = X1, 
        s1 = X1 - 1) 
    for(i in 2:n_params){ 
    new_df <- append(call to new_df, 
      mutate(mi = Xi*Xi-1, 
        si = mi-mi-1) 
    } 
    } 
} 

Однако, я не могу понять, как совместить lazyeval interp и setNames чтобы позволить ссылаться на предыдущее мутированное значение.

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

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

ответ

0

Не самая красивая вещь, но это работает:

n_params = 3 

xx1 = df %>% 
mutate(m1 = X1, 
     s1 = X1 - 1) 

for (i in 2:n_params) { 
xx1 = xx1 %>% 
    mutate_(.dots = setNames(list(varval = paste0("m", i - 1, " * X", i)), 
          paste0("m", i))) %>% 
    mutate_(.dots = setNames(list(varval = paste0("m", i, " - m", i - 1)), 
          paste0("s", i))) 
} 

Там, наверное, много лучших способов использовать lazyeval. Надеюсь, кто-то покажет хороший ответ, но это не соответствует xx произведенный в вашем вопросе (для n_params = 3):

identical(xx, xx1) 
# [1] TRUE 
+0

Я думаю, что у меня может быть вопрос о версии. Если я попробую это, xx1 создаст m2 и s2, но когда он попытается создать m3, он не сможет найти m2. error 'Ошибка: object 'm2' not found' Я запускаю: R версии 3.2.2 (2015-08-14) с lazyeval_0.1.10 dplyr_0.4.3; ошибка относится к Rcpp, и это Rcpp_0.12.1. 'stop (struct (list (message =" object 'm2' not found ", call = NULL, cppstack = NULL).Names = c ("message", "call", "cppstack" ), class = c ("Rcpp :: eval_error", "C++ Error", "error", "condition" ))) ' – jessi

+0

My Версия Rcpp равна 0.12.2, но в противном случае мы сопоставим. – Gregor

+0

Моя ошибка, у меня была 'xx1 = xx%>%' - это никогда не сработает. Спасибо за решение этого. * мой большой вопрос * Интересно, почему 'list' работает и сохраняет значения и имена, но' interp' не сделал. – jessi

Смежные вопросы