基于If条件与Mutate创建列:代码未达预期输出,是否存在错误?
你的代码确实存在几个关键问题,导致无法得到预期结果,我来逐一拆解并给出修正方案:
1. Base R if 语句处理向量条件的错误
你用 rd_3$results.cluster=='Visitor' | rd_3$results.cluster=='Employee' 作为 if 的判断条件,但这个表达式返回的是与数据框行数一致的逻辑向量(每一行对应一个TRUE/FALSE)。而Base R的if语句只能接受长度为1的逻辑值,此时R会自动只取向量的第一个元素来判断分支,这就意味着:
- 如果数据框第一行的
results.cluster是Visitor/Employee,只会执行第一个分支,所有行都按这个逻辑处理(不管实际cluster是什么) - 如果第一行是Guest,只会执行第二个分支,同样所有行都套用Guest的逻辑
- 如果第一行是其他值,两个分支都不会执行,
visit_no.列根本不会被创建
这完全不符合你"按不同cluster分别处理"的需求。
2. 分组逻辑的不合理性
在第一个分支中,你按device_id, hotel, start_date分组,这意味着每个分组内的start_date都是完全相同的。此时diff.Date(start_date) > 0的结果全是FALSE,cumsum(c(T, diff.Date(start_date) > 0))的结果就会全是1,根本无法实现"按日期递增计数访问次数"的目的。这显然是分组逻辑写错了,你应该按device_id, hotel分组,然后在组内根据start_date的差异计算访问次数。
修正后的代码
我们可以用dplyr的case_when结合分组操作,实现按不同cluster分别计算visit_no.的需求,同时避免上述问题:
library(dplyr) # 先按device_id和hotel分组,再根据cluster类型计算visit_no. rd_3 <- rd_3 %>% group_by(device_id, hotel) %>% mutate( visit_no. = case_when( # 对Visitor和Employee:相邻日期不同则计数+1 results.cluster %in% c("Visitor", "Employee") ~ cumsum(c(TRUE, diff(start_date) > 0)), # 对Guest:相邻日期差超过1天则计数+1 results.cluster == "Guest" ~ cumsum(c(TRUE, diff(start_date) > 1)), # 处理其他未定义的cluster类型,返回NA TRUE ~ NA_integer_ ) ) %>% ungroup() # 取消分组(如果后续不需要保留分组状态的话)
代码说明:
- 用
group_by(device_id, hotel)确保我们是对同一个设备、同一个酒店的记录进行访问次数计数 case_when可以针对每一行的results.cluster值应用不同的计算逻辑,完美替代原来的错误if分支diff(start_date)直接计算相邻行的日期差,不需要额外调用diff.Date(dplyr会自动处理日期类型)- 最后用
ungroup()取消分组,避免后续操作受到分组状态的影响
如果你的原始需求确实需要对Visitor/Employee按start_date额外分组(虽然看起来不合理),可以调整分组逻辑为group_by(device_id, hotel, results.cluster),再在case_when中处理不同的计数规则,但我更倾向于上面的修正方案,因为它更符合"按用户类型统计同一设备在酒店的访问次数"的常规需求。
内容的提问来源于stack exchange,提问作者Yogesh Kumar

