R语言中根据观测日期提取对应及历史温度列值的技术问询
提取指定日期的温度数据解决方案
问题描述
现有数据框Sp,包含Site(样点编号)、Date(物种观测日期)列,其余列以dd/mm/yyyy格式的日期为列名,存储对应日期的温度数据。需要为每一行提取:
Date列对应日期的温度(命名为T0(YYYY-MM-DD))- 观测日期前1天的温度(命名为
T-1(YYYY-MM-DD)) - 观测日期前2天的温度(命名为
T-2(YYYY-MM-DD))
同时保留Site和Date列。
数据构造代码:
set.seed(0) Sp <- data.frame(Site = c(seq(1:50)), Date = c(seq(as.Date("2012/01/01"), by = "day", length.out = 50)), "01/01/2012" = c(runif(n = 50, min = 20, max = 40)), "02/01/2012" = c(runif(n = 50, min = 20, max = 40)), "03/01/2012" = c(runif(n = 50, min = 20, max = 40)), "04/01/2012" = c(runif(n = 50, min = 20, max = 40)), "05/01/2012" = c(runif(n = 50, min = 20, max = 40)), "06/01/2012" = c(runif(n = 50, min = 20, max = 40)), "07/01/2012" = c(runif(n = 50, min = 20, max = 40)), "08/01/2012" = c(runif(n = 50, min = 20, max = 40)))
解决方案(Base R 版本)
逻辑直观,无需额外依赖包:
# 1. 将温度列的列名转换为标准YYYY-MM-DD格式,方便匹配 temp_col_names <- colnames(Sp)[-c(1, 2)] temp_dates <- as.Date(temp_col_names, format = "%d/%m/%Y") colnames(Sp)[-c(1, 2)] <- as.character(temp_dates) # 2. 初始化结果数据框,保留Site和Date列 result_df <- data.frame(Site = Sp$Site, Date = Sp$Date) # 3. 逐行提取对应日期的温度值 for (row_idx in 1:nrow(Sp)) { current_date <- as.character(Sp$Date[row_idx]) prev1_date <- as.character(Sp$Date[row_idx] - 1) # 前1天日期 prev2_date <- as.character(Sp$Date[row_idx] - 2) # 前2天日期 # 提取温度并添加到结果框,列名按示例格式命名 result_df[row_idx, paste0("T0(", current_date, ")")] <- Sp[row_idx, current_date] result_df[row_idx, paste0("T-1(", prev1_date, ")")] <- Sp[row_idx, prev1_date] result_df[row_idx, paste0("T-2(", prev2_date, ")")] <- Sp[row_idx, prev2_date] } # 查看前几行结果 head(result_df)
解决方案(Tidyverse 版本)
适合习惯现代R编程风格的用户:
library(tidyverse) library(lubridate) # 1. 转换温度列名为标准日期格式 Sp_tidy <- Sp %>% rename_with(~ as.character(dmy(.)), .cols = -c(Site, Date)) # 2. 逐行提取目标日期温度并格式化列名 result_df <- Sp_tidy %>% rowwise() %>% mutate( # 计算目标日期 t0_date = Date, t_min1_date = Date - days(1), t_min2_date = Date - days(2), # 提取对应温度值 T0 = pick(as.character(t0_date)), T_min1 = pick(as.character(t_min1_date)), T_min2 = pick(as.character(t_min2_date)), # 生成带日期的列名 T0_col = paste0("T0(", as.character(t0_date), ")"), T_min1_col = paste0("T-1(", as.character(t_min1_date), ")"), T_min2_col = paste0("T-2(", as.character(t_min2_date), ")") ) %>% ungroup() %>% # 整理成目标格式 select(Site, Date, T0_col, T0, T_min1_col, T_min1, T_min2_col, T_min2) %>% pivot_longer(cols = ends_with("_col"), names_to = "type", values_to = "col_name") %>% pivot_wider(names_from = col_name, values_from = matches("T0|T_min")) %>% select(Site, Date, starts_with("T0"), starts_with("T-1"), starts_with("T-2")) # 查看前几行结果 head(result_df)
两种方法均能生成符合要求的输出,Base R版本更易理解,tidyverse版本则更简洁高效。
内容的提问来源于stack exchange,提问作者RGR_288
相关产品推荐
相关产品推荐

