2015-08-09 62 views
2

data.table分组我试图跨越ň因素估计在data.table一些参数。虽然我熟悉使用by功能以某个因素执行操作,为多个顺序因素做这件事会导致一些问题。在多个连续的因素

作为一个例子,与组简化

df <- data.table(Group = c(rep("A", 2), rep("B", 3), rep("C", 2), rep("D", 4), "E", rep("F", 4)), Variable = round(rnorm(16), 2)) 

Group Variable 
1:  A  0.13  
2:  A  0.26 
3:  B -1.36 
4:  B -0.78 
5:  B -0.92 
6:  C  0.00 
7:  C -2.49 
8:  D -1.85 
9:  D  0.37 
10: D -0.57 
11: D  1.42 
12: E -0.72 
13: F -1.04 
14: F  1.86 
15: F  0.49 
16: F  1.61 

使用df[, mean(Variable), by = Group]将给出每一组的平均值。但是,我想计算以前的组的平均值。
我试过使用M[, zoo::rollapply(Variable, n, mean), by = Group],但是,因为这些组使用固定的不同尺寸n将不起作用。

想要什么功能类似于df[, mean(Variable), by = "This Group and previous n Groups]

我想实现(为ň = 3的情况)的输出会看起来像

Group Variable 
1:  A NA  
2:  A NA 
3:  B NA 
4:  B NA 
5:  B NA 
6:  C 0.13 
7:  C 0.13 
8:  D -1.36 
9:  D -1.36 
10: D -1.36 
11: D -1.36 
12: E 0 
13: F -1.85 
14: F -1.85 
15: F -1.85 
16: F -1.85 

任何帮助,将不胜感激。

+0

如果您正在寻找'rollapply'使用可变窗宽,你应该检查这个问题:http://stackoverflow.com/questions/21368245/adaptive-rolling-window-function-top-performance-in-r请记住,目前最高的upvoted答案不回答这个问题。 – jangorecki

+0

此链接有帮助。 –

回答

4
library(data.table) 
library(RcppRoll) 
df1 <- df[, .(n=.N, S=sum(Variable)), by = Group] 
df1[, NewVariable:=roll_sum(S, 3, align="right", fill=NA)/roll_sum(n, 3, align="right", fill=NA),] 
df[df1, on="Group"] 
    Group Variable n  S NewVariable 
1:  A -0.63 2 -0.45   NA 
2:  A  0.18 2 -0.45   NA 
3:  B -0.84 3 1.09   NA 
4:  B  1.60 3 1.09   NA 
5:  B  0.33 3 1.09   NA 
6:  C -0.82 2 -0.33 0.04428571 
7:  C  0.49 2 -0.33 0.04428571 
8:  D  0.74 4 2.52 0.36444444 
9:  D  0.58 4 2.52 0.36444444 
10:  D -0.31 4 2.52 0.36444444 
11:  D  1.51 4 2.52 0.36444444 
12:  E  0.39 1 0.39 0.36857143 
13:  F -0.62 4 -1.75 0.12888889 
14:  F -2.21 4 -1.75 0.12888889 
15:  F  1.12 4 -1.75 0.12888889 
16:  F -0.04 4 -1.75 0.12888889 

我希望我的解决方案是不言自明的。

dplyr相当于是

df %>% 
    group_by(Group) %>% 
    summarise(n=n(), S=sum(Variable)) %>% 
    mutate(NewVar=roll_sum(S, 3, align="right", fill=NA)/roll_sum(n, 3, align="right", fill=NA)) %>% 
    left_join(df, by="Group") 

数据

set.seed(1) 
df <- data.table(Group = c(rep("A", 2), rep("B", 3), rep("C", 2), rep("D", 4), "E", rep("F", 4)), Variable = round(rnorm(16), 2)) 

包装信息

[1] RcppRoll_0.2.2 data.table_1.9.5 
+1

回想起来,创建一个新的df1与变量总和按组,然后合并与原来的df似乎很明显。但是,这个解决方案超越了我。这里的dplyr解决方案(以及其他有用的答案)使我相信现在是时候为这个软件包付出一些努力。感谢所有有用的方向。 –

+0

很高兴帮助。 – Khashaa

1

如果您愿意将data.table转换为data.frame并执行此过程,我可以为您提供帮助。 看看这个例子,并逐步执行这些命令,看看它是如何工作的。这个例子涉及你提到的n = 3的情况。

library(dplyr) 

df <- data.frame(Group = c(rep("A", 2), rep("B", 3), rep("C", 2), rep("D", 4), "E", rep("F", 4)), 
       Variable = round(rnorm(16), 2)) 


df %>% group_by(Group) %>% 
    do(data.frame(df2 = df)) %>% 
    mutate(diff = as.numeric(Group) - as.numeric(df2.Group)) %>% 
    filter(diff %in% 0:2) %>% 
    mutate(unique_pairs = n_distinct(diff)) %>% 
    filter(unique_pairs ==3) %>% 
    mutate(Mean = mean(df2.Variable)) %>% 
    filter(diff==0) %>% 
    select(Group, Mean) %>% 
    ungroup 

哲学只是创建“组”名称之间的所有组合,然后创建一些有用的列进行过滤。 您可以使用for循环执行此过程,但我预计它会变慢。

如果你真的想与data.table(背景仍然dplyr但data.table结构)上班试试这个:

library(dplyr) 
library(data.table) 

df <- data.table(Group = c(rep("A", 2), rep("B", 3), rep("C", 2), rep("D", 4), "E", rep("F", 4)), 
        Variable = round(rnorm(16), 2)) 

df = df %>% mutate(Group2 = as.numeric(as.factor(Group))) 

df %>% 
    group_by(Group2, Group) %>% 
    do(data.table(df2 = df)) %>% 
    mutate(diff = Group2 - df2.Group2) %>% 
    filter(diff %in% 0:2) %>% 
    group_by(Group2, Group) %>% 
    mutate(unique_pairs = n_distinct(diff)) %>% 
    filter(unique_pairs ==3) %>% 
    group_by(Group2, Group) %>% 
    mutate(Mean = mean(df2.Variable)) %>% 
    filter(diff==0) %>% 
    select(Group2, Group, Mean) %>% 
    ungroup 

这里data.table不喜欢的因素,所以我不得不使用数字而不是字母作为组变量。 此外,每次发生变异后,我不得不再次组(这是一个已知的问题dplyr当你想在后台data.table工作)。哲学是完全一样的。

+0

*此外,每次mutate后,我不得不再次组合(这是一个已知的data.table问题)* - 你可以链接与此相关的data.table回购问题? – jangorecki

+0

是的,我见过那些: https://github.com/hadley/dplyr/issues/919和 http://stackoverflow.com/questions/31363269/different-behavior-for-group-by- for-data-table-vs-data-frame – AntoniosK

+0

我不会称之为*已知的data.table问题*,而是一个*已知的dplyr问题*。 – jangorecki

2

这可能不是最有效的方式,但它的工作原理:

首先,让我们来设置重复性的种子:

set.seed(1038) 
> df 
    Group Variable 
1:  A -0.86 
2:  A  0.57 
3:  B  0.10 
4:  B -1.57 
5:  B  1.73 
6:  C -0.56 
7:  C  0.54 
8:  D -1.71 
9:  D -0.47 
10:  D -1.00 
11:  D  1.03 
12:  E -0.47 
13:  F -1.06 
14:  F -2.06 
15:  F -0.57 
16:  F  1.70 

现在消除铸造Group为整数,其用于n-1更多实实在在的,然后通过grp_no凝聚所有的多次观察:

setkey(df[ , grp_no := as.integer(as.factor(Group))], grp_no) 
df_ttls <- df[ , .(ttl = sum(Variable), .N), by = grp_no] 
> df_ttls 
    grp_no ttl N 
1:  1 -0.29 2 
2:  2 0.26 3 
3:  3 -0.02 2 
4:  4 -2.15 4 
5:  5 -0.47 1 
6:  6 -1.99 4 

现在创建你寻求使用的加权平均值shift

df_ttls[ , lag3avg := rowSums(sapply(0:2, shift, x = ttl))/ 
       rowSums(sapply(0:2, shift, x = N))] 

和合并回完整数据集:

df[df_ttls, lag3avg := i.lag3avg][ ] 
    Group Variable grp_no  lag3avg 
1:  A -0.86  1   NA 
2:  A  0.57  1   NA 
3:  B  0.10  2   NA 
4:  B -1.57  2   NA 
5:  B  1.73  2   NA 
6:  C -0.56  3 -0.007142857 
7:  C  0.54  3 -0.007142857 
8:  D -1.71  4 -0.212222222 
9:  D -0.47  4 -0.212222222 
10:  D -1.00  4 -0.212222222 
11:  D  1.03  4 -0.212222222 
12:  E -0.47  5 -0.377142857 
13:  F -1.06  6 -0.512222222 
14:  F -2.06  6 -0.512222222 
15:  F -0.57  6 -0.512222222 
16:  F  1.70  6 -0.512222222 

注意,这可以很容易地扩展到功能:

k_lag_avg <- function(k){ 
    df[df_ttls[ , .(grp_no, rowSums(sapply(1:k - 1L, shift, x = ttl))/ 
        rowSums(sapply(1:k -1L, shift, x = N)))], 
    paste0("lag", k, "avg") := i.V2] 
} 

k_lag_avg(5L); df[ ] 
    Group Variable grp_no  lag3avg lag5avg 
1:  A -0.86  1   NA   NA 
2:  A  0.57  1   NA   NA 
3:  B  0.10  2   NA   NA 
4:  B -1.57  2   NA   NA 
5:  B  1.73  2   NA   NA 
6:  C -0.56  3 -0.007142857   NA 
7:  C  0.54  3 -0.007142857   NA 
8:  D -1.71  4 -0.212222222   NA 
9:  D -0.47  4 -0.212222222   NA 
10:  D -1.00  4 -0.212222222   NA 
11:  D  1.03  4 -0.212222222   NA 
12:  E -0.47  5 -0.377142857 -0.2225000 
13:  F -1.06  6 -0.512222222 -0.3121429 
14:  F -2.06  6 -0.512222222 -0.3121429 
15:  F -0.57  6 -0.512222222 -0.3121429 
16:  F  1.70  6 -0.512222222 -0.3121429 
+0

这是一个很好的解决方案@MichaelChirico。 –