如何在R中使用melt函数时按日期+小时顺序输出数据框?
解决melt后数据按date和hour正确排序的问题
首先咱们先理清楚两个核心问题:日期列的类型和hour列的顺序识别,这两点都会直接影响最终的排序结果。
1. 先修正日期列的类型问题
你当前的date列是字符型(因为原始数据里的日期是字符串格式),虽然短日期看起来排序正常,但如果日期范围扩大,字符排序会出现逻辑错误(比如"2018-03-31"会排在"2018-04-01"后面,因为字符串是按单个字符逐位比较的)。所以第一步必须把date转成标准日期类型:
mydf$date <- as.Date(mydf$date)
2. 处理hour列的顺序识别问题
你提到R无法识别hour的顺序,这是因为melt生成的hour列默认是字符型或无序因子:
- 如果是字符型,对于
h1-h5这种命名,字符排序刚好能正常工作,但如果后续出现h10,字符排序会把h10放在h2前面,完全不符合逻辑; - 如果是无序因子,排序时会依赖默认的因子水平顺序(也就是原始列名的顺序,这里其实是对的,但如果数据里的hour不是按顺序出现,或者你需要强制固定顺序,就需要转成有序因子)。
方法一:melt后转成有序因子再排序
这是最稳妥的方式,能明确指定hour的逻辑顺序:
library(reshape2) library(dplyr) # 用arrange函数做排序 # 按你的代码完成melt转换 mynewdf <- melt(mydf, id.vars = c("name","date"), variable.name = "hour", value.name = "desiredName", measure.vars = names(mydf[,3:7])) # 将hour转为有序因子,手动指定水平顺序 mynewdf$hour <- factor(mynewdf$hour, levels = paste0("h", 1:5), # 强制h1到h5的顺序 ordered = TRUE) # 按date升序、hour升序排序 mynewdf_sorted <- arrange(mynewdf, date, hour)
方法二:不用因子,直接按hour中的数字排序
如果不想用因子,可以提取hour里的数字部分来排序,这种方式更灵活,适合hour命名不规则的场景:
library(stringr) mynewdf_sorted <- arrange(mynewdf, date, as.numeric(str_extract(hour, "\\d+")))
这里str_extract(hour, "\\d+")会从h3这类字符串里提取出数字3,转成数值后排序就完全符合逻辑了。
方法三:melt时手动指定measure.vars的顺序(可选)
其实reshape2的melt函数中,measure.vars的顺序会决定hour列的因子水平顺序(如果hour是因子类型的话)。你当前的measure.vars = names(mydf[,3:7])已经是按h1到h5的顺序,所以默认生成的hour因子水平是正确的,但如果原始列顺序不对,或者需要调整,可以手动指定顺序:
mynewdf <- melt(mydf, id.vars = c("name","date"), variable.name = "hour", value.name = "desiredName", measure.vars = c("h1", "h2", "h3", "h4", "h5")) # 手动固定列顺序
不过这只能保证hour的因子水平正确,最终的排序还是需要用arrange来按date和hour完成。
总结
- 一定要先把
date转成Date类型,避免字符排序的逻辑错误; - 处理
hour顺序的话,转成有序因子是最直观的方式,提取数字排序则更灵活; melt本身不能直接完成排序,但可以通过指定measure.vars的顺序来保证hour的因子水平正确,之后再用arrange完成最终的排序需求。
内容的提问来源于stack exchange,提问作者alvaropr
相关产品推荐
相关产品推荐

