2017-09-30 5 views
1

Ist es möglich, einen Anfangswert für Reduce anzugeben, ohne dass dieser in den Datenrahmen eingefügt wird?R dplyr: Mutieren mit Reduce mit init, nach group_by

Zum Beispiel mit Funktion:

f <- function(x, y) if (y<0) -x * y else x + y 

auf Datenrahmen Acting:

set.seed(0) 
    df <- c(-0.9, sample(c(-0.9, 1:3), 9, replace = TRUE)) %>% tibble() 
    names(df) <- "x" 
    df <- df %>% mutate(id = 'a') 
    df$id[6:10] <- 'b' 
    df <- df %>% group_by(id) %>% mutate(sumprod = Reduce(f, x, acc=TRUE)) %>% ungroup() 
    df$target <- c(0, 3, 4, 5, 7, 3, 2.7, 5.7, 8.7, 10.7) 
    df 

# A tibble: 10 x 4 
     x id sumprod target 
    <dbl> <chr> <dbl> <dbl> 
1 -0.9  a -0.9 0.0 
2 3.0  a  2.1 3.0 
3 1.0  a  3.1 4.0 
4 1.0  a  4.1 5.0 
5 2.0  a  6.1 7.0 
6 3.0  b  3.0 3.0 
7 -0.9  b  2.7 2.7 
8 3.0  b  5.7 5.7 
9 3.0  b  8.7 8.7 
10 2.0  b 10.7 10.7 

Ziel ist Spalte target. Ich habe versucht mit init mit Reduce, aber das fügt ein zusätzliches Element hinzu.

Reduce(f, df$x[1:5], acc=TRUE, init=0) 
[1] 0 0 3 4 5 7 

dies erzeugt einen Fehler innerhalb mutieren Verwendung:

> df <- df %>% group_by(id) %>% mutate(sumprod = Reduce(f, x, acc=TRUE, init=0)) %>% ungroup() 
Error in mutate_impl(.data, dots) : 
    Column `sumprod` must be length 5 (the group size) or one, not 6 

Antwort

2

Wenn init angegeben wird, fügt sie an den Anfang Reduzieren Sie logisch (wenn links und rechts Verfahrens) oder das Ende von x sind. Wenn Sie das Element nicht benötigen, können Sie tail(..., -1) verwenden können, um das erste Element zu entfernen:

df %>% 
    group_by(id) %>% 
    mutate(sumprod = tail(Reduce(f, x, acc=TRUE, init=0), -1)) %>% 
    ungroup() 

# A tibble: 10 x 4 
#  x id sumprod target 
# <dbl> <chr> <dbl> <dbl> 
# 1 -0.9  a  0.0 0.0 
# 2 3.0  a  3.0 3.0 
# 3 1.0  a  4.0 4.0 
# 4 1.0  a  5.0 5.0 
# 5 2.0  a  7.0 7.0 
# 6 3.0  b  3.0 3.0 
# 7 -0.9  b  2.7 2.7 
# 8 3.0  b  5.7 5.7 
# 9 3.0  b  8.7 8.7 
#10 2.0  b 10.7 10.7 
2

Mit tidyverse gibt es accumulate von purrr

library(tidyverse) 
df %>% 
    group_by(id) %>% 
    mutate(sumprod = accumulate(.x = x, .f = f, .init = 0)[-1]) %>% 
    ungroup 
# A tibble: 10 x 3 
#  x id sumprod 
# <dbl> <chr> <dbl> 
# 1 -0.9  a  0.0 
# 2 3.0  a  3.0 
# 3 1.0  a  4.0 
# 4 1.0  a  5.0 
# 5 2.0  a  7.0 
# 6 3.0  b  3.0 
# 7 -0.9  b  2.7 
# 8 3.0  b  5.7 
# 9 3.0  b  8.7 
#10 2.0  b 10.7 
Verwandte Themen