如何用cbind将for循环结果保存为Data Frame?按小时拆分能耗数据
解决方法:把长格式小时能耗数据转成宽格式
嘿,我明白你遇到的问题了——用for循环+cbind处理的时候,因为不同小时的记录数可能不一致,导致行列不匹配报错对吧?其实你的需求本质是长格式数据转宽格式,R里有专门的工具来搞定这个,根本不用写循环,既简洁又不容易出错。
问题出在哪?
你原来的代码里,每次循环提取某个小时的heat值再cbind,但如果某天缺失了某个小时的数据,不同小时对应的向量长度就不一样,cbind要求所有输入的列行数必须相同,自然就报错了。而且手动循环也很麻烦,不如用专门的重塑函数来处理。
靠谱的解决方案
方法1:用tidyr的pivot_wider(推荐,属于tidyverse生态)
首先确保你装了tidyr包(如果没装的话先安装):
install.packages("tidyverse") # 或者单独装tidyr:install.packages("tidyr") library(tidyr)
第一步,我们需要给每一天生成一个唯一标识,这样同一天的24小时记录能归到同一行里。从你的数据来看,wk+month+dyid组合起来就能唯一标识一天:
# 创建日期唯一ID dfSub$date_id <- paste(dfSub$wk, dfSub$month, dfSub$dyid, sep = "_")
然后用pivot_wider直接转成宽格式:
df_wide <- pivot_wider( data = dfSub, id_cols = date_id, # 按日期分组,每行对应一天 names_from = hr, # 把hr的取值(1-24)作为新列的列名 values_from = heat # 把heat的值填充到对应的列里 ) # 可选:把列名改成hr1、hr2...hr24(默认是1、2...24) colnames(df_wide)[-1] <- paste0("hr", colnames(df_wide)[-1])
方法2:用reshape2的dcast
如果你习惯用reshape2包,也可以这么写:
install.packages("reshape2") library(reshape2) # 同样先创建日期ID dfSub$date_id <- paste(dfSub$wk, dfSub$month, dfSub$dyid, sep = "_") # 转换格式 df_wide <- dcast( data = dfSub, date_id ~ hr, # 行是date_id,列是hr的取值 value.var = "heat" # 填充的值来自heat列 ) # 重命名列名 colnames(df_wide)[-1] <- paste0("hr", colnames(df_wide)[-1])
结果验证
用你给的示例数据跑上面的代码,得到的df_wide前两行就是你想要的效果:
date_id hr1 hr2 hr3 hr4 hr5 hr6 hr7 hr8 hr9 hr10 hr11 hr12 hr13 hr14 hr15 hr16 hr17 hr18 hr19 hr20 hr21 hr22 hr23 hr24 1 2_1_1 81 61 53 51 30 31 51 90 114 110 126 113 104 107 117 90 114 83 82 61 34 52 41 52 2 2_1_2 44 50 33 41 33 43 40 8 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
(第二行的hr9到hr24因为示例数据里没给,所以自动填充成了NA,这很合理)
内容的提问来源于stack exchange,提问作者Tymo
相关产品推荐
相关产品推荐

