【问题标题】:R sum of aggregate columns found in another column在另一列中找到的聚合列的 R 总和
【发布时间】:2017-11-22 09:14:57
【问题描述】:

鉴于这些数据,前 4 列(rowid、order、line、special),我需要创建一个列,numSpecial 如下:

rowid   order    line    special    numSpecial
1       A        01      X          1
2       B        01                 0
3       B        02      X          2
4       B        03      X          2
5       C        01      X          1
6       C        02                 0

其中 numSpecial 是通过对每个特殊订单(值 = X)的次数求和来确定的,假设 order-line 本身是特殊的,否则为 0。

我首先尝试添加一个简单地将“order”与“X”连接起来的列,称之为orderX,看起来像:

orderX
AX
BX
BX
BX
CX
CX

然后在orderx中做order & special的求和:

df$numSpecial <- sum(paste(order, special, sep = "") %in% orderx)

但这不起作用,它返回每个订单的所有行的结果总和:

numSpecial
4
4
4
4
4
4

然后我尝试了 as.data.table,但我没有得到预期的结果:

as.data.table(mydf)[, numSpecial := sum(paste(order, special, sep = "") %in% orderx), by = rowid]

但是每行只返回 1 而不是总和:

numSpecial
1
0
1
1
1
0

我在哪里做错了?我不认为我不应该创建该 orderX 列,但我无法弄清楚如何正确计算。它类似于excel中的countif,很容易做到。

【问题讨论】:

  • 库(dplyr); df %>% group_by(order) %>% mutate(numSpecial = ifelse(special=="X", sum(special=="X"), 0))`
  • 另一个是有道理的,但是当我尝试这个时,我得到了上面 2 次尝试的组合,即 numSpecial 结果为 [4,0,4,4,4,0]。跨度>

标签: r sum data.table


【解决方案1】:

可能有多种方法,但您可以将其乘以存在 "X" 的 TRUE/FALSE 标志:

dat[, numSpecial := sum(special == "X") * (special == "X"), by=order]
dat

#   rowid order line special numSpecial
#1:     1     A    1       X          1
#2:     2     B    1                  0
#3:     3     B    2       X          2
#4:     4     B    3       X          2
#5:     5     C    1       X          1
#6:     6     C    2                  0

你也可以做一些不同的事情,比如:

dat[, numSpecial := 0L][special == "X", numSpecial := .N, by=order]

dat 在哪里:

library(data.table)
dat <- structure(list(rowid = 1:6, order = c("A", "B", "B", "B", "C", 
"C"), line = c(1L, 1L, 2L, 3L, 1L, 2L), special = c("X", "", 
"X", "X", "X", "")), .Names = c("rowid", "order", "line", "special"
), row.names = c(NA, -6L), class = "data.frame")
setDT(dat)

【讨论】:

  • @KJackson - 我可以在这里验证它是否有效。我现在已经使我的示例完全可重现(请参阅最后的编辑)以表明代码正在运行。
  • 现在可以使用了,谢谢。可惜只能接受一个答案。不过对于那些寻找另一种方法的人来说,这是一个很好的例子。
【解决方案2】:

您可以将ave 与虚拟变量一起使用(仅填充1s):

df$numSpecial <- ifelse(df$special == "X", ave(rep(1,nrow(df)), df$order, df$special, FUN = length), 0)

 df
#  rowid order line special numSpecial
#1     1     A    1       X          1
#2     2     B    1                  0
#3     3     B    2       X          2
#4     4     B    3       X          2
#5     5     C    1       X          1
#6     6     C    2                  0

请注意,我在没有 numSpecial 列的情况下读取了您的数据。

【讨论】:

  • 不错!没有考虑使用 ave(),而是用 1 填充,它可以工作。为了安全起见,将使用我的完整数据集进行验证。
【解决方案3】:

使用dplyr 包:

library(dplyr)

df %>% group_by(order) %>% 
  mutate(numSpecial = ifelse(special=="X", sum(special=="X"), 0))
  rowid  order special numSpecial
1     1      A       X          1
2     2      B                  0
3     3      B       X          2
4     4      B       X          2
5     5      C       X          1
6     6      C                  0

【讨论】:

  • 我没有得到你显示的结果,使用我的实际数据。它返回我上面尝试的汇编,汇总结果并为每个结果设置 special=="X",例如numSpecial[4,0,4,4,4,0].
  • 尝试使用您提供的示例数据在干净的 R 会话中运行代码,如果您仍然得到不同的结果,请告诉我。
  • 现在可以使用了,谢谢。可惜只能接受一个答案。不过我喜欢在这里使用 dplyr!
【解决方案4】:

仅使用基本 R 的另一种选择是使用聚合:

# Your data
df <- data.frame(rowid = 1:6, order = c("A", "B", "B", "B", "C", "C"), special = c("X", "", "X", "X", "X", ""))

# Make the counts    
dat <- with(df,aggregate(x=list(answer=special),by=list(order=order,special=special),FUN=function(x) sum(x=="X")))

# Merge back to original dataset:
dat.fin <- merge(df,dat,by=c('order','special'))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-08
    • 1970-01-01
    • 2019-05-07
    • 1970-01-01
    • 2018-05-22
    相关资源
    最近更新 更多