【问题标题】:Calculate sum of a column by ID based on the value of another column in R根据R中另一列的值按ID计算一列的总和
【发布时间】:2015-03-19 14:12:55
【问题描述】:

我有一些看起来像这样的数据:

E_Add  Action  ActionType  Call  Callback  Email
xxxx   Task    Call        1     0         0
xxxx   Task    Call        1     0         0
xxxx   Event   Start       0     0         0
xxxx   Task    Call        1     0         0
xxxx   Event   Trial       0     0         0
yyyy   Task    Call        1     0         0
yyyy   Task    Callback    0     1         0
yyyy   Task    Email       0     0         1
yyyy   Task    Call        1     0         0
yyyy   Event   Start       0     0         0

我希望它看起来像这样:

E_Add  Action  ActionType  Call  Callback  Email CallSum CallbackSum EmailSum
xxxx   Task    Call        1     0         0
xxxx   Task    Call        1     0         0     2
xxxx   Event   Start       0     0         0     
xxxx   Task    Call        1     0         0     1
xxxx   Event   Trial       0     0         0
yyyy   Task    Call        1     0         0            
yyyy   Task    Callback    0     1         0             1
yyyy   Task    Email       0     0         1                         1
yyyy   Task    Call        1     0         0     2
yyyy   Event   Start       0     0         0

我的意思是它看起来可能会有所不同,但这就是我想要的想法。我想通过电子邮件汇总“通话”、“回拨”和“电子邮件”,并将它们放在一个新列中。但我想在每次点击“操作”列中的“事件”时重置“呼叫”、“回调”或“电子邮件”的总和,当然是通过电子邮件执行此操作。

【问题讨论】:

  • 您的描述不清楚。为什么在 callSum 列中,对于第一封电子邮件,总和第一次写在事件行上,而不是第二次写在事件行上?

标签: r


【解决方案1】:

您想要的输出不是很清楚,但我认为这可以满足您的需要(您也有两次 Email 列)

library(data.table)
cols <- c("Call", "Callback", "Email") # Choose columns to modify

第一个解决方案(简单版)

setDT(df)[, paste0(cols, "Sum") := 
            lapply(.SD, function(x) c(rep(0L, .N - 1L), sum(x))),
            by = .(E_Add, cumsum(Action == "Event")), 
            .SDcols = cols][]

#     E_Add   Action ActionType Call Callback Email.1 CallSum CallbackSum EmailSum
#  1:  xxxx   Task       Call    1        0       0       0           0          0
#  2:  xxxx   Task       Call    1        0       0       2           0          0
#  3:  xxxx  Event      Start    0        0       0       0           0          0
#  4:  xxxx   Task       Call    1        0       0       1           0          0
#  5:  xxxx  Event      Trial    0        0       0       0           0          0
#  6:  yyyy   Task       Call    1        0       0       0           0          0
#  7:  yyyy   Task   Callback    0        1       0       0           0          0
#  8:  yyyy   Task      Email    0        0       1       0           0          0
#  9:  yyyy   Task       Call    1        0       0       2           1          1
# 10:  yyyy  Event      Start    0        0       0       0           0          0

第二种解决方案以匹配您的精确输出

setDT(df)[, paste0(cols, "Sum") := 
            lapply(.SD, function(x) {
            if(any(x == 1L)){
              indx <- max(which(x == 1L))
              x[indx] <- sum(x) 
              x[-indx] <- 0L
              x
              } else 0L
           }), 
            by = .(E_Add, cumsum(Action == "Event")), 
           .SDcols = cols][]

#     E_Add   Action ActionType Call Callback Email.1 CallSum CallbackSum EmailSum
#  1:  xxxx   Task       Call    1        0       0       0           0          0
#  2:  xxxx   Task       Call    1        0       0       2           0          0
#  3:  xxxx  Event      Start    0        0       0       0           0          0
#  4:  xxxx   Task       Call    1        0       0       1           0          0
#  5:  xxxx  Event      Trial    0        0       0       0           0          0
#  6:  yyyy   Task       Call    1        0       0       0           0          0
#  7:  yyyy   Task   Callback    0        1       0       0           1          0
#  8:  yyyy   Task      Email    0        0       1       0           0          1
#  9:  yyyy   Task       Call    1        0       0       2           0          0
# 10:  yyyy  Event      Start    0        0       0       0           0          0

编辑每条评论(如果你想在Event上显示总和

df[, paste0(cols, "Sum") := 
     lapply(.SD, function(x) c(rep(0L, .N - 1L), sum(x))),
     by = .(E_Add, cumsum(c(FALSE, (Action == "Event")[-length(Action)]))), 
          .SDcols = cols][]

#     E_Add Action ActionType Call Callback Email CallSum CallbackSum EmailSum
#  1:  xxxx   Task       Call    1        0     0       0           0        0
#  2:  xxxx   Task       Call    1        0     0       0           0        0
#  3:  xxxx  Event      Start    0        0     0       2           0        0
#  4:  xxxx   Task       Call    1        0     0       0           0        0
#  5:  xxxx  Event      Trial    0        0     0       1           0        0
#  6:  yyyy   Task       Call    1        0     0       0           0        0
#  7:  yyyy   Task   Callback    0        1     0       0           0        0
#  8:  yyyy   Task      Email    0        0     1       0           0        0
#  9:  yyyy   Task       Call    1        0     0       0           0        0
# 10:  yyyy  Event      Start    0        0     0       2           1        1

【讨论】:

  • 我认为这应该可行,因为我怀疑第三行的 CallSum 是错字。
  • @akrun 是的,我也认为这是一个错字,因此,这似乎与 exact 输出匹配。
  • 谢谢!!尽管我对这个问题的解释很糟糕,但这仍然很有效。
  • 如果我想将总和输出到“事件”所在的行怎么办?
【解决方案2】:
df = structure(list(Email = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L), .Label = c("xxxx", "yyyy"), class = "factor"), Action = structure(c(2L, 
2L, 1L, 2L, 1L, 2L, 2L, 2L, 2L, 1L), .Label = c("Event", "Task"
), class = "factor"), ActionType = structure(c(1L, 1L, 4L, 1L, 
5L, 1L, 2L, 3L, 1L, 4L), .Label = c("Call", "Callback", "Email", 
"Start", "Trial"), class = "factor"), Call = c(1L, 1L, 0L, 1L, 
0L, 1L, 0L, 0L, 1L, 0L), Callback = c(0L, 0L, 0L, 0L, 0L, 0L, 
1L, 0L, 0L, 0L), Emails = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 
0L)), .Names = c("Email", "Action", "ActionType", "Call", "Callback", 
"Emails"), class = "data.frame", row.names = c(NA, -10L))

df$CallSum=''
df$CallBackSum=''
df$EmailSum=''

CSum =0
CBSum =0
ESum =0
for(i in 1:nrow(df)){

CSum = CSum+ df[[4]][i]
CBSum = CBSum+ df[[5]][i]
ESum = ESum+ df[[6]][i]

if(df[[2]][i] == 'Event'){

#
df[[7]][i] = CSum
df[[8]][i] = CBSum
df[[9]][i] = ESum

#clear out vars
CSum =0
CBSum =0
ESum =0
}

}



   Email Action ActionType Call Callback Emails CallSum CallBackSum EmailSum
1   xxxx   Task       Call    1        0      0                             
2   xxxx   Task       Call    1        0      0                             
3   xxxx  Event      Start    0        0      0       2           0        0
4   xxxx   Task       Call    1        0      0                             
5   xxxx  Event      Trial    0        0      0       1           0        0
6   yyyy   Task       Call    1        0      0                             
7   yyyy   Task   Callback    0        1      0                             
8   yyyy   Task      Email    0        0      1                             
9   yyyy   Task       Call    1        0      0                             
10  yyyy  Event      Start    0        0      0       2           1        1

【讨论】:

  • 您的循环如何知道“通过电子邮件”执行此操作?
  • 你怎么能把它放到一个函数中,然后通过“电子邮件”将它应用到数据中?
【解决方案3】:

这是我的尝试。我最终覆盖了这三个列(即 Call、Callback 和 Email.1)。这可能是获得您所追求的一种方式。最初,我在第一个 mutate 中创建了一个组变量。我按电子邮件和组对数据进行了分组,并计算了 Call、Callback 和 Email.1 的总和。最后,我想要零而不是空白。所以我在最后的mutate中使用了replace()

library(zoo)
library(dplyr)

group_by(mydf, Email) %>%
mutate(group = ifelse(Action == "Event", row_number(), NA),
       group = na.locf(group, fromLast = TRUE)) %>%
group_by(Email, group) %>%
mutate_each(funs(sum(., na.rm = TRUE)), Call:Email.1) %>%
mutate_each(funs(replace(., which(Action != "Event"), 0)), Call:Email.1) %>%
ungroup %>%
select(-group)

#   Email Action ActionType Call Callback Email.1
#1   xxxx   Task       Call    0        0       0
#2   xxxx   Task       Call    0        0       0
#3   xxxx  Event      Start    2        0       0
#4   xxxx   Task       Call    0        0       0
#5   xxxx  Event      Trial    1        0       0
#6   yyyy   Task       Call    0        0       0
#7   yyyy   Task   Callback    0        0       0
#8   yyyy   Task      Email    0        0       0
#9   yyyy   Task       Call    0        0       0
#10  yyyy  Event      Start    2        1       1

数据

mydf <- structure(list(Email = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L), .Label = c("xxxx", "yyyy"), class = "factor"), Action = structure(c(2L, 
2L, 1L, 2L, 1L, 2L, 2L, 2L, 2L, 1L), .Label = c("Event", "Task"
), class = "factor"), ActionType = structure(c(1L, 1L, 4L, 1L, 
5L, 1L, 2L, 3L, 1L, 4L), .Label = c("Call", "Callback", "Email", 
"Start", "Trial"), class = "factor"), Call = c(1L, 1L, 0L, 1L, 
0L, 1L, 0L, 0L, 1L, 0L), Callback = c(0L, 0L, 0L, 0L, 0L, 0L, 
1L, 0L, 0L, 0L), Email.1 = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 
0L, 0L)), .Names = c("Email", "Action", "ActionType", "Call", 
"Callback", "Email.1"), class = "data.frame", row.names = c(NA, 
-10L))

【讨论】:

    猜你喜欢
    • 2017-08-20
    • 2022-01-23
    • 1970-01-01
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多