使用R实现不同长度数据框列间值映射与赋值的问题求解
R实现非等值滚动匹配时间列并赋值分数
实现逻辑
你的需求是按id匹配两个数据框,为df1的每个time值匹配df2中第一个大于等于该time值的time2对应的score2,属于按组滚动匹配场景,以下是3种常用实现方案:
前置准备:构造示例数据
# 构造第一个数据框df1 df1 <- structure(list(id = c(4375, 4375, 4375, 4375), time = c(0, 88, 96, 114)), class = "data.frame", row.names = c(NA, -4L)) # 构造第二个数据框df2 df2 <- structure(list(id2 = c(4375, 4375, 4375, 4375, 4375, 4375, 4375, 4375, 4375, 4375), time2 = c(0, 2, 87, 88, 94, 97, 101, 104, 109, 114), score2 = c(0.028, 0.057, 0.057, 0.057, 0.057, 0.057, 0.057, 0.085, 0.085, 0.085)), class = "data.frame", row.names = c(NA, -10L))
方案1:基础R实现(无需额外安装包)
# 先将df2按id和time2升序排序 df2_sorted <- df2[order(df2$id2, df2$time2), ] # 按id分组匹配对应分数 df1$score <- mapply(function(id, t) { # 筛选同id的df2子集 sub_df2 <- df2_sorted[df2_sorted$id2 == id, ] # 找到第一个大于等于t的time2的位置,减1e-9避免浮点精度误差 idx <- findInterval(t - 1e-9, sub_df2$time2) + 1 # 超出匹配范围时取最后一个score值 if(idx > nrow(sub_df2)) idx <- nrow(sub_df2) return(sub_df2$score2[idx]) }, df1$id, df1$time)
方案2:data.table实现(效率最高,适合百万级以上大数据量)
library(data.table) # 转换为data.table格式 setDT(df1) setDT(df2) # 设置连接键,roll=-Inf表示匹配最近的>=当前time的time2,mult="first"取第一个匹配结果 setkey(df2, id2, time2) result <- df2[df1, on = .(id2 = id, time2 >= time), mult = "first"][, .(id = id2, time = time2, score = score2)]
方案3:tidyverse实现(适合tidy生态习惯用户)
library(dplyr) library(purrr) result <- df1 %>% group_by(id) %>% mutate(score = map_dbl(time, ~{ df2 %>% filter(id2 == cur_group()$id, time2 >= .x) %>% slice(1) %>% pull(score2) })) %>% ungroup()
注:你给出的期望结果中最后一个time值为116属于笔误,原df1最后一个time为114,按匹配逻辑对应score为0.085,和你期望的score结果一致。
内容的提问来源于stack exchange,提问作者kam
相关产品推荐
相关产品推荐

