4

我正在计算dplyr::summarize销售数据的数据框。我进行分组(S,D,Y),然后在每个组中计算第 5..43 周的中位数和平均值,然后将它们合并回父 df。变量 X 是销售额。X 永远不会是 NA(即 df 中的任何地方都没有明确的 NA),但是如果该 S、D、Y 和一组周没有数据(如没有销售),则根本不会有这些值的行在 df 中(这意味着该特定参数集的销售额为零)。换句话说,在任何结构缺失的行中估算 X=0 (但我希望我不需要melt/cast原始 df,以避免膨胀。类似于cast(fill....,add.missing=T)or caret::preProcess())。

关于我的代码习惯的两个问题:

  1. 使用 summarise 是否比 更好dplyr::filter,因为 filter 会物理删除行,所以我必须将结果分配给df.tmp然后将其左连接回原始 df (如下所示)?此外,在每行汇总计算中重复的大子集表达式使代码更难阅读。我是否应该担心(或不)缓存子集操作的行或逻辑索引,在一般情况下我可能会计算说 n=20 个新的汇总变量?

  2. 并非所有 S、D、Y 组和过滤器的组合(对于那几周)都有行,那么如何获取汇总以替换任何缺失行上的 NA?目前我做如下。

抱歉,代码和数据集都是专有的,但这里是代码习惯用法,下面是您应该首先运行以生成示例数据的代码:

# Compute median, mean of X across wks 5..43, for that set of S,D,Y-values
# Issue a) filter() or repeatedly use subset() within each calculation?
df.tmp <- df %.% group_by(S,D,Y) %.% filter(Week>=5 & Week<=43) %.%
  summarize(ysd_med543_X  = median(X),
            ysd_mean543_X = mean(X)
           ) %.% ungroup()

# Issue b) how to replace NAs in groups where the group_by-and-filter gave empty output?
# can you merge this code with the summarize above?
df <- left_join(df, df.tmp, copy=F)
newcols <- match(c('ysd_mean543_X','ysd_med543_X'), names(df))
df[!complete.cases(df[,newcols]), newcols] <- c(0.0,0.0)

并首先运行它以生成示例数据:

set.seed(1234)

rep_vector <- function(vv, n) {
  unlist(as.vector(lapply(vv, function(...) {rep(...,n)} )))
}

n=7
m=3
df = data.frame(S = rep_vector(10:12, n), D = 20:26,
                Y = rep_vector(2005:2007, n),
                Week = round(52*runif(m*n)),
                X = 4e4*runif(m*n) + 1e4 )

# Now drop some rows, to model structurally missing rows
I <- sort(sample(1:nrow(df),0.6*nrow(df)))
df = df[I,]

require(dplyr)
4

1 回答 1

8

我认为这与您在评论下链接的功能没有任何关系(因为 IIUC 该功能与未使用的因子水平有关)。过滤数据后,IMOsummarise不应该(或者说不能?)将它们包含在结果中(除了factors)。您应该在他们的项目页面上与开发人员澄清这一点。


我绝不是dplyr专家,但我认为,首先,最好filter先跟随group_by + summarise。否则,您将为每个组进行过滤,这是不必要的。那是:

df.tmp <- df %.% filter(Week>=5 & Week<=43) %.% group_by(S,D,Y) %.% ...

这只是为了让您在未来的任何情况下都知道它。


IMO,最好在mutate这里使用而不是summarise,因为它会消除对left_joinIIUC 的需要。那是:

df.tmp <- df %.% group_by(S,D,Y) %.% mutate(
             md_X = median(X[Week >=5 & Week <= 43]), 
             mn_X = mean(X[Week >=5 & Week <= 43]))

在这里,我们仍然有更换 NA/NaN 的问题。这里没有简单/直接的子分配方法。因此,您将不得不ifelse再次使用 IIUC。但如果mutate支持表达式,那就更好了。

我的想法是这样的:

df.tmp <- df %.% group_by(S,D,Y) %.% mutate(
              { tmp = Week >= 5 & Week <= 43;
                md_X = ifelse(length(tmp), median(X[tmp]), 0), 
                md_Y = ifelse(length(tmp), mean(X[tmp]), 0)
              })   

因此,我们可能不得不以这种方式解决:

df.tmp = df %.% group_by(S,D,Y) %.% mutate(tmp = Week >=5 & Week <= 43)
df.tmp %.% mutate(md_X = ifelse(tmp[1L], median(X), 0), 
                  mn_X = ifelse(tmp[1L], mean(X), 0))

或者把事情放在一起:

df %.% group_by(S,D,Y) %.% mutate(tmp = Week >=5 & Week <= 43, 
       md_X = ifelse(tmp[1L], median(X), 0), 
       mn_X = ifelse(tmp[1L], median(X), 0)) 

#     S  D    Y Week        X   tmp     md_X     mn_X
# 1  10 20 2005    6 22107.73  TRUE 22107.73 22107.73
# 2  10 23 2005   32 18751.98  TRUE 18751.98 18751.98
# 3  10 25 2005   33 31027.90  TRUE 31027.90 31027.90
# 4  10 26 2005    0 46586.33 FALSE     0.00     0.00
# 5  11 20 2006   12 43253.80  TRUE 43253.80 43253.80
# 6  11 22 2006   27 28243.66  TRUE 28243.66 28243.66
# 7  11 23 2006   36 20607.47  TRUE 20607.47 20607.47
# 8  11 24 2006   28 22186.89  TRUE 22186.89 22186.89
# 9  11 25 2006   15 30292.27  TRUE 30292.27 30292.27
# 10 12 20 2007   15 40386.83  TRUE 40386.83 40386.83
# 11 12 21 2007   44 18049.92 FALSE     0.00     0.00
# 12 12 26 2007   16 35856.24  TRUE 35856.24 35856.24

这不需要df.tmp.

高温高压

于 2014-05-03T08:12:00.973 回答