这就是我的数据框架的样子。
dt <- read.table(text='
Name ActivityType GrpID
John Sale 1
John Sale 2
John Webinar 3
Kyle Email 1
Kyle Seminar 2
Kyle Sale 3
Kyle Webinar 4
Kyle Sale 5
Tom Email 1
Tom Video 2
Tom Seminar 3
', header=T, row.names = NULL)
我想做三件事。
返回第一个ActivityType不在的剩余组&#34; Sale&#34;但是有一个ActivityType =&#34; Sale&#34;在稍后的某些行中(如1&amp; 2中所述)并且仅显示结果直到ActivityType = Sale的第一个实例。所以它应该显示
Name ActivityType GrpID
Kyle Email 1
Kyle Seminar 2
Kyle Sale 3
它不必是所述的3个步骤。我只需要最终输出。我在考虑在data.table中使用SD功能,但不知道如何添加这些条件。我将非常感谢你的帮助。
答案 0 :(得分:7)
在1 Sunday
2 Monday
3 Tuesday
4 Wednesday
5 Thursday
6 Friday
7 Saturday
:
data.table
(请注意,第三种情况包含前两种,所以我假设你想要三种不同的输出......否则只能坚持到最后一种情况)
答案 1 :(得分:3)
使用dplyr
这将适用于上面的示例
dt %>%
group_by(Name) %>%
filter( sum((GrpID == 1 & ActivityType=='Sale')) == 0 ) %>%
filter( sum(ActivityType=='Sale') > 0 ) %>%
filter( GrpID <= min(GrpID[ActivityType == 'Sale'])) %>%
ungroup
#Source: local data frame [3 x 3]
#
# Name ActivityType GrpID
# (fctr) (fctr) (int)
#1 Kyle Email 1
#2 Kyle Seminar 2
#3 Kyle Sale 3
虽然可能有更简洁的方法。
编辑:我添加了输出,ungroup
删除了分组。
编辑2:根据MichaelChirico的建议
dt %>%
group_by(Name) %>%
filter( !any(ActivityType == 'Sale' & GrpID == 1) ) %>% # 1
filter( any(ActivityType == 'Sale') ) %>% # 2
filter( GrpID <= min(GrpID[ActivityType == 'Sale'])) %>% # 3
ungroup
上述解决方案使用any
代替sum
(%>%
是管道运算符)。这并不是说这不能提高效率。如果有人建议更有效和/或更具可读性的dplyr
解决方案,我将很乐意再次更新。
编辑3
以下是基于@MichaelChirico的评论/解决方案的第3项的替代解决方案。这将所有3个条件合并到一个过滤器语句中(不使用上面的渐进过滤)。
dt %>%
group_by(Name) %>%
mutate(x = (ActivityType == 'Sale') ) %>%
filter( !x[1],
any(x),
row_number() <= which.max(x)) %>%
ungroup %>%
select(-x)
答案 2 :(得分:1)
# For those who prefer to roll their own
result.list <- by(dt, dt$Name, FUN = function(x) {
f <- match("Sale", x$ActivityType)
if(!is.na(f) & (f != 1) ) return(head(x, f))
})
result.df <- do.call(rbind, result.list)