使用case_when跨多列计算不同call_type的音符时长
声乐音符数据集时长计算解决方案
问题背景
我有一个大型声乐音符数据集,需要根据call_type计算每个音符(行)的时长,编程经验有限。
数据集示例
note_type call_type begin.time end.time 1 doublet 314.2205 314.2344 2 doublet 314.2856 314.3273 3 squeak 316.2678 316.2799 1 triplet 316.3476 316.3928 1 triplet 318.4582 318.4713 2 triplet 318.5413 318.5853
时长计算规则
- doublet:时长 = note_type2的end.time - note_type1的begin.time
- squeak:时长 = end.time - begin.time
- triplet:时长 = 连续3个triplet中第3个音符的end.time - 第1个音符的begin.time
已有代码
all_notes %>% mutate(call_dur = case_when(call_type == "doublet" & note_type == "1" ~ (lead(end.time) - begin.time), call_type == "squeak" ~ (end.time - begin.time)))
目前卡在triplet的计算上,因为triplet的note_type组合不固定(比如1,1,2、1,2,2等),不知道怎么跨3行计算时长,希望得到实现triplet时长计算的方法,最终理想的call_dur列结果如下:
note_type call_type begin.time end.time call_dur 1 doublet 314.2205 314.2344 0.0139 2 doublet 314.2856 314.3273 na 3 squeak 316.2678 316.2799 0.0121 1 triplet 316.3476 316.3928 2.2377 1 triplet 318.4582 318.4713 na 2 triplet 318.5413 318.5853 na
解决方案
可以用dplyr的分组和窗口函数处理triplet的情况,核心是先标记连续的triplet组,再在组内针对性计算时长,完整代码如下:
library(dplyr) all_notes %>% # 标记连续的triplet组:call_type切换时组号递增 mutate(triplet_group = cumsum(call_type != lag(call_type, default = ""))) %>% # 按分组处理时长计算 group_by(triplet_group) %>% mutate( call_dur = case_when( # 保留原有doublet计算逻辑 call_type == "doublet" & note_type == "1" ~ lead(end.time) - begin.time, # 保留原有squeak计算逻辑 call_type == "squeak" ~ end.time - begin.time, # triplet仅组内第一行计算时长:取组内最后一行的end.time减当前begin.time call_type == "triplet" & row_number() == 1 ~ last(end.time) - begin.time, # 其余情况设为NA TRUE ~ NA_real_ ) ) %>% ungroup() %>% select(-triplet_group) # 移除临时分组列
代码说明
triplet_group列:通过cumsum和lag函数识别连续的triplet片段,确保每一组连续的3个triplet被归为同一组。- 分组计算逻辑:在每个triplet组内,仅给第一行赋值时长,用
last(end.time)获取组内最后一个音符的结束时间,减去第一行的开始时间。 - 逻辑整合:保留了你已实现的doublet和squeak计算规则,保证整体逻辑统一。
运行这段代码后,即可得到符合预期的call_dur列结果。
内容的提问来源于stack exchange,提问作者user23793029
相关产品推荐
相关产品推荐

