【问题标题】:Ragged rowSums in RR中的参差不齐的rowSums
【发布时间】:2016-11-23 18:01:02
【问题描述】:

我正在尝试为实际列做一个rowSum。但是,对于某些观察,我想包括截至UpTo 日期的值。这是数据框:

dat <- structure(list(Company = c("ABC", "DEF", "XYZ"), UpTo = c(NA, 
"Q2", "Q3"), Actual.Q1 = c(100L, 80L, 100L), Actual.Q2 = c(50L, 
75L, 50L), Forecast.Q3 = c(80L, 50L, 80L), Forecast.Q4 = c(90L, 
80L, 100L)), .Names = c("Company", "UpTo", "Actual.Q1", "Actual.Q2", 
"Forecast.Q3", "Forecast.Q4"), class = "data.frame", row.names = c("1", 
"2", "3"))

  Company UpTo Actual.Q1 Actual.Q2 Forecast.Q3 Forecast.Q4
1     ABC   NA       100        50          80          90
2     DEF   Q2        80        75          50          80
3     XYZ   Q3       100        50          80         100
  • 对于公司ABC,由于没有UpTo 日期,它只是Actual.Q1 + Actual.Q2,即150。
  • 对于公司DEF,由于UpTo的日期是Q2,所以它将是Actual.Q1 + Actual.Q2,即155。
  • 对于公司XYZ,由于UpTo的日期是Q3,所以它将是Actual.Q1 + Actual.Q2 + Forecast.Q3,即230。

生成的数据框如下所示:

  Company UpTo Actual.Q1 Actual.Q2 Forecast.Q3 Forecast.Q4 SumRecent
1     ABC   NA       100        50          80          90       150
2     DEF   Q2        80        75          50          80       155
3     XYZ   Q3       100        50          80         100       230

我尝试使用rowSums 函数。但是,它不会使变量UpTo 生效。任何帮助表示赞赏。谢谢!

【问题讨论】:

  • 如果是 NA,则只有 Q1 + Q2,因为如果没有指定最新的,我们只需要实际值。

标签: r rowsum


【解决方案1】:

这是一种可能性:

df$SumRecent <- sapply(1:nrow(df), function(x) {sum(df[x,3:ifelse(is.na(grep(df[x,2], colnames(df))[1]), 4, grep(df[x,2], colnames(df))[1])])})


#   Company UpTo Actual.Q1 Actual.Q2 Forecast.Q3 Forecast.Q4 SumRecent
# 1     ABC <NA>       100        50          80          90       150
# 2     DEF   Q2        80        75          50          80       155
# 3     XYZ   Q3       100        50          80         100       230

我们正在使用grep 来寻找UpTo (df[x,2]) 列名称中df (colnames(df)) 中的值的匹配。如果我们找到它,我们会得到总和,如果我们没有找到它,我们只需将第 3 列和第 4 列中的值相加。

【讨论】:

  • 根据经验,我真的非常讨厌自己在 data.frame 中使用数字引用。始终使用名称 - 相信我!在这种情况下,如果由于列位置发生变化而导致事情中断,那么简洁不值得失去理智。
  • @BrandonBertelsen:我同意它会带来一些问题,但是在这种情况下,不使用数字引用,我们必须查看以 QXXX 结尾的每个列名,确保它们在增加订单等等,这似乎使问题变得过于复杂。 (或者你有更快的解决方案吗?)我假设 data.frame 的格式是固定的以回答这个问题。
  • 一般来说,这不是批评,只是对在 R 中这样的编程提出警告。 Stackoverflow 的答案有很大的影响力。因此,注意事项对新程序员很有用:)
  • @BrandonBertelsen 哦,我没有把它当作批评对不起,如果我的评论让你这么想,我很感激你的谨慎
【解决方案2】:

我们可以使用二进制加权行和。

UpTo <- as.character(dat$UpTo)  ## in case you have factor column
UpTo[is.na(UpTo)] <- "Q2"  ## replace `NA` to "Q2"
w <- outer(as.integer(substr(UpTo, 2, 2)), 1:4, ">=")
#     [,1] [,2]  [,3]  [,4]
#[1,] TRUE TRUE FALSE FALSE
#[2,] TRUE TRUE FALSE FALSE
#[3,] TRUE TRUE  TRUE FALSE

我们有一个逻辑矩阵。但它不影响算术计算,因为TRUE 为 1,FALSE 为 0。然后我们进行加权行求和:

X <- data.matrix(dat[3:6])
dat$SumRecent <- rowSums(X * w)

#  Company UpTo Actual.Q1 Actual.Q2 Forecast.Q3 Forecast.Q4 SumRecent
#1     ABC <NA>       100        50          80          90       150
#2     DEF   Q2        80        75          50          80       155
#3     XYZ   Q3       100        50          80         100       230

这种方法的优势在于它的速度/效率,因为它是完全矢量化的。这种方法超级快。您可以参考Fast way to create a binary matrix with known number of 1 each row in R中的基准测试结果。

【讨论】:

    【解决方案3】:

    这也应该有效:

    df$UpTo <- as.character(df$UpTo)
    df$SumRecent <- apply(df, 1, function(x) ifelse(is.na(x[2]), sum(as.integer(x[3:4])), 
                                               sum(as.integer(x[3:(grep(x[2], names(df)))]))))
    df
    
    #     Company UpTo Actual.Q1 Actual.Q2 Forecast.Q3 Forecast.Q4 SumRecent
    #1     ABC <NA>       100        50          80          90       150
    #2     DEF   Q2        80        75          50          80       155
    #3     XYZ   Q3       100        50          80         100       230
    

    【讨论】:

      【解决方案4】:

      另一种使用数据表的方法:

      require(data.table)
      dat <- fread('Company UpTo Actual.Q1 Actual.Q2 Forecast.Q3 Forecast.Q4
                   ABC   NA       100        50          80          90
                   DEF   Q2        80        75          50          80
                   XYZ   Q3       100        50          80         100')
      
      dat[, SumRecent:= ifelse(is.na(UpTo), Actual.Q1 + Actual.Q2,  
                                            sum(.SD[, grepl(paste0("Q[1-", substring(UpTo, 2), "]$"), names(.SD)), with = F]) ), by = Company]
      

      【讨论】:

        猜你喜欢
        • 2013-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-09
        相关资源
        最近更新 更多