2016-10-24 7 views
0

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

library(tidyverse) 

df <- tribble(
    ~y_val, ~z_val, 
    2, 4, 
    5, 3, 
    8, 2, 
    1, 1, 
    9, 3) 

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

fun_a <- function(x, y, z, times = 1) { 

    df <- data.frame() 
    for (i in 1:times) { 
     x <- x * 2 + i * x 
     y <- y/3 + i * y 
     z <- z + 1 + z * i 
    d <- data.frame(x, y, z) 
    df <- rbind(df, d) 
    } 
    return(df) 
} 

fun_b <- function(x, y, z, times = 1) { 
    df <- fun_a(x, y, z, times) 
    x_r <- sum(df$x) 
    y_r <- sum(df$y) 
    z_r <- sum(df$z) 
    val <- x_r/y_r * z_r 
    return(val) 
} 

При запуске пользовательской функции:

df %>% 
    mutate(test = fun_b(x = 1, y = y_val, z = z_val, times = 1)) 

Каждый мутировавший значение test показывает то же значение (13,95). Это не имеет смысла! Например, первая строка в тибе (y_val = 2, z_val = 4) должна быть 10.125!

fun_b(x = 1, y = 2, z = 4, times = 1) 

Что здесь происходит?

+0

Вам просто нужно сгруппировать rollise, т. е. 'df%>% rowwise()%>% mutate (test = fun_b (x = 1, y = y_val, z = z_val, times = 1))' или просто вынимать вызовы 'sum', чтобы ваш функции векторизуемы – alistaire

ответ

1

Вы можете сгруппировать построчно, так что функция получает отдельно для каждой строки:

df %>% 
    rowwise() %>% 
    mutate(test = fun_b(x = 1, y = y_val, z = z_val, times = 1)) 

## Source: local data frame [5 x 3] 
## Groups: <by row> 
## 
## # A tibble: 5 × 3 
## y_val z_val  test 
## <dbl> <dbl> <dbl> 
## 1  2  4 10.12500 
## 2  5  3 3.15000 
## 3  8  2 1.40625 
## 4  1  1 6.75000 
## 5  9  3 1.75000 

или редактировать fun_b получить так это векторизация, или просто пусть R:

df %>% mutate(test = Vectorize(fun_b)(x = 1, y = y_val, z = z_val, times = 1)) 

## # A tibble: 5 × 3 
## y_val z_val  test 
## <dbl> <dbl> <dbl> 
## 1  2  4 10.12500 
## 2  5  3 3.15000 
## 3  8  2 1.40625 
## 4  1  1 6.75000 
## 5  9  3 1.75000 
1

Попробуйте следующее

df %>% 
    group_by(y_val, z_val) %>% 
    mutate(test = fun_b(x = 1, y = y_val, z = z_val, times = 1)) 

Это заставило меня 10.125.

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

  • Нет связанных вопросов^_^