如何从分数与时间列中找出每人最早记录的分数及时间(R语言)
问题描述
我为每个个体记录了两类带时间的分数,部分个体有两条不同时间的分数记录。作为R语言初学者,希望找出每人最早记录的分数类型及对应时间,并在数据框中新增两列分别存储该分数类型与时间。
原始数据如下:
df <- structure(list(PersonID = c(111, 222, 333), ScoreOne = c(1, 3, NA), ScoreOneTime = structure(c(1654147200, 1654148400, 1654149600), class = c("POSIXct", "POSIXt"), tzone = "GMT"), ScoreTwo = c(3, NA, 1), ScoreTwoTime = structure(c(1654137960, NA, 1654146000), class = c("POSIXct", "POSIXt"), tzone = "GMT")), class = "data.frame", row.names = c(NA, -3L))
解决方案
方法一:使用tidyverse工具(推荐初学者)
tidyverse的函数逻辑直观,适合初学者处理数据转换与分组计算,步骤如下:
- 若未安装tidyverse,先运行
install.packages("tidyverse")安装 - 将宽格式数据转为长格式,把两类分数和对应时间整合到统一列中
- 过滤掉无分数的NA记录
- 按PersonID分组,筛选每组中时间最早的记录
- 将结果合并回原数据,新增目标列
代码实现:
library(tidyverse) # 转换为长格式并清理无效记录 long_df <- df %>% pivot_longer( cols = -PersonID, names_to = c(".value", "Type"), names_pattern = "(Score|ScoreTime)(One|Two)" ) %>% drop_na(Score) # 提取每个个体的最早记录 earliest_records <- long_df %>% group_by(PersonID) %>% slice_min(ScoreTime, n = 1) %>% ungroup() %>% mutate(EarliestScoreType = paste0("Score", Type)) %>% select(PersonID, EarliestScoreType, EarliestScoreTime = ScoreTime) # 合并回原数据 result_df <- df %>% left_join(earliest_records, by = "PersonID") # 查看最终结果 print(result_df)
运行后新增的两列说明:
EarliestScoreType:该个体最早记录的分数类型(ScoreOne/ScoreTwo)EarliestScoreTime:对应最早记录的时间
方法二:基础R实现(无需额外包)
如果不想加载第三方包,可通过基础R的循环与条件判断处理:
# 初始化新增列 df$EarliestScoreType <- NA_character_ df$EarliestScoreTime <- as.POSIXct(NA, tz = "GMT") # 逐个处理每个个体 for (pid in unique(df$PersonID)) { # 提取当前个体的时间与对应分数类型 times <- c(df$ScoreOneTime[df$PersonID == pid], df$ScoreTwoTime[df$PersonID == pid]) types <- c("ScoreOne", "ScoreTwo") # 筛选有效时间记录 valid_idx <- !is.na(times) if (any(valid_idx)) { # 找出最早时间的索引并赋值 earliest_pos <- which.min(times[valid_idx]) df$EarliestScoreType[df$PersonID == pid] <- types[valid_idx][earliest_pos] df$EarliestScoreTime[df$PersonID == pid] <- times[valid_idx][earliest_pos] } } # 查看结果 print(df)
内容的提问来源于stack exchange,提问作者Ashok.S
相关产品推荐
相关产品推荐

