根据月份日期向数据表添加一个季节列

4

我正在使用data.table,尝试创建一个名为“season”的新列,根据名为“MonthName”的列生成对应的季节,例如夏季、冬季等。

我想知道是否有更有效的方法基于月份值向数据表中添加一个季节列。

以下是300,000个观察结果中的前6个,请假设表名为“dt”。

    rrp         Year   Month Finyear hourminute AvgPriceByTOD MonthName
1: 35.27500     1999     1    1999      00:00      33.09037       Jan
2: 21.01167     1999     1    1999      00:00      33.09037       Jan
3: 25.28667     1999     2    1999      00:00      33.09037       Feb
4: 18.42334     1999     2    1999      00:00      33.09037       Feb
5: 16.67499     1999     2    1999      00:00      33.09037       Feb
6: 18.90001     1999     2    1999      00:00      33.09037       Feb

我尝试了以下代码:

dt[, Season :=  ifelse(MonthName = c("Jun", "Jul", "Aug"),"Winter", ifelse(MonthName = c("Dec", "Jan", "Feb"), "Summer", ifelse(MonthName = c("Sep", "Oct", "Nov"), "Spring" , ifelse(MonthName = c("Mar", "Apr", "May"), "Autumn", NA))))]

返回结果:

 rrp totaldemand   Year Month Finyear hourminute AvgPriceByTOD MonthName Season
1: 35.27500     1999     1    1999      00:00      33.09037       Jan     NA
2: 21.01167     1999     1    1999      00:00      33.09037       Jan Summer
3: 25.28667     1999     2    1999      00:00      33.09037       Feb Summer
4: 18.42334     1999     2    1999      00:00      33.09037       Feb     NA
5: 16.67499     1999     2    1999      00:00      33.09037       Feb     NA
6: 18.90001     1999     2    1999      00:00      33.09037       Feb Summer

我遇到了错误:

Warning messages:
1: In MonthName == c("Jun", "Jul", "Aug") :
  longer object length is not a multiple of shorter object length
2: In MonthName == c("Dec", "Jan", "Feb") :
  longer object length is not a multiple of shorter object length
3: In MonthName == c("Sep", "Oct", "Nov") :
  longer object length is not a multiple of shorter object length
4: In MonthName == c("Mar", "Apr", "May") :
  longer object length is not a multiple of shorter object length 

同时,由于我不知道的原因,其中一些夏季月份被正确地标记为“夏季”,但其他月份则被标记为NA。例如,第1行和第2行都应该是夏季,但返回的结果不同。

提前感谢!


1
请使用MonthName %in% c("Jun",...)而不是= - SymbolixAU
2
这并不是一个“错误”,而是一个“警告”。 - SymbolixAU
这并不是理想的做法,因为它会创建并删除重复的级别,但我通常会在数字月份上使用 cut 函数:droplevels(cut(dt$Month, breaks = c(0, 2, 5, 8, 11, 13), labels = c('冬季', '春季', '夏季', '秋季', '冬季'))). - alistaire
2个回答

9

一种非常直接的方法是使用查找表将月份名称映射到季节:

# create a named vector where names are the month names and elements are seasons
seasons <- rep(c("winter","spring","summer","fall"), each = 3)
names(seasons) <- month.abb[c(6:12,1:5)] # thanks thelatemail for pointing out month.abb
seasons
#     Jun      Jul      Aug      Sep      Oct      Nov      Dec      Jan 
#"winter" "winter" "winter" "spring" "spring" "spring" "summer" "summer" 
#     Feb      Mar      Apr      May 
#"summer"   "fall"   "fall"   "fall" 

使用它:

dt[, season := seasons[MonthName]]

数据:

dt <- setDT(read.table(text="    rrp         Year   Month Finyear hourminute AvgPriceByTOD MonthName
1: 35.27500     1999     1    1999      00:00      33.09037       Jan
2: 21.01167     1999     1    1999      00:00      33.09037       Jan
3: 25.28667     1999     2    1999      00:00      33.09037       Feb
4: 18.42334     1999     2    1999      00:00      33.09037       Feb
5: 16.67499     1999     2    1999      00:00      33.09037       Feb
6: 18.90001     1999     2    1999      00:00      33.09037       Feb",
   header = TRUE, stringsAsFactors = FALSE))

哈,我猜你应该在南半球的某个地方。 - alistaire
@alistaire - 我猜是美国,注意:“fall” ;) - SymbolixAU
@allistaire,根据OP的映射,我将月份映射到季节。 "秋天"是我的贡献,哈哈。 - Jota
哎呀,没注意到……我想应该把我的上一条评论应用到原帖上! - alistaire
3
顺便提一下,base R 中有 month.abb,可以节省输入时间 - month.abb[c(6:12,1:5)] 可以按月份顺序输出月份的缩写。 - thelatemail
非常好,Jota!又快又顺畅。 - Gin_Salmon

5

需要打一点字,但代码很高效

dt[MonthName %in% c("Jun","Jul","Aug"), Season := "Winter"]
dt[MonthName %in% c("Dec","Jan","Feb"), Season := "Summer"]
dt[MonthName %in% c("Sep","Oct","Nov"), Season := "Spring"]
dt[is.na(MonthName), Season := "Autumn"]

在此,我们将按引用分配数据表的子集。

相比于许多嵌套的ifelse,我更喜欢这种方法。


如果你想检查一个值是否在向量中,你必须使用%in%。请看以下不同行为:

myVec <- c("a","b","c")

"a" == myVec
[1] TRUE FALSE FALSE

"a" %in% myVec
[1] TRUE

2
可能更有效的方法是创建一个查找表,然后像这样连接一次:ref <- data.table(MonthName=month.abb[c(12,1:11)], season=rep(c("Summer","Autumn","Winter","Spring"), each=3)); dt[ref, on="MonthName"] - thelatemail
@thelatemail - 类似于Jota的答案,我给了一个+1 :) - SymbolixAU
糟糕...我在写评论时页面没有刷新。 - thelatemail
感谢您对%in%和==之间区别的解释,非常有帮助,这也曾让我困扰过! - Gin_Salmon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接