【问题标题】:Combining weather data with records with different date ranges in R将天气数据与 R 中具有不同日期范围的记录相结合
【发布时间】:2015-01-28 00:36:55
【问题描述】:

我有 2 个数据集 - 第一个有每日天气信息,包括平均温度和加热度日。对于需要的每一天,我都有一套完整的天气数据。天气数据的小 sn-p 如下所示:

weather:

weather.station | date       | temp | HDD
A               | 11/30/2013 | 30   | 35
A               | 12/01/2013 | 28   | 37

第二个数据集包含多个家庭的数据,每个家庭都有单独的日期范围,显示每天的燃料消耗量。例如:

home.bills:

home.id | start.date | end.date   | electric.usage | weather.station
1       | 11/15/2013 | 12/14/2013 |  80            | A
1       | 12/15/2013 | 1/14/2014  |  85            | A
2       | 11/18/2013 | 12/15/2013 |  60            | A
2       | 12/16/2013 | 1/13/2014  |  57            | A

我正在寻找一种有效的方法来批量合并这两个数据集,因此我可以根据天气条件扩展 home.bills 信息(例如,日期范围内的平均温度和日期范围内的总和 HDD) .

输出可能如下所示:

output:

home.id | start.date | end.date   | electric.usage | mean.temp | sum.HDD
1       | 11/15/2013 | 12/14/2013 |  80            |   32.8    |  937
1       | 12/15/2013 | 1/14/2014  |  85            |   29.7    |  1122
2       | 11/18/2013 | 12/15/2013 |  60            |   31.7    |  944
2       | 12/16/2013 | 1/13/2014  |  57            |   28.8    |  1201

谁能建议一种 dplyer 方法来加入这两个数据集?我知道如何进行总结,但我不知道如何在一个日期范围内连接两个数据。

【问题讨论】:

  • 不明白 Q 你将如何组合数据。例如。如何利用weather数据中的temp?这两个日期属于home.id == 1 的第一个日期间隔。您是否有想要的输出并将其发布在此处以便更好地理解?
  • OP 指出“例如,日期范围内的平均温度和日期范围内的总和 HDD”,因此他在寻找什么似乎很清楚。 (我承认这个例子可能更具可重复性。)
  • 今后请不要永远发布这样的数据(用管道分隔列)。将其导入 R 是一场噩梦。而是发布例如dput(weather) 的输出。

标签: r


【解决方案1】:

这里有两种方法可以做到这一点。第一个使用sqldf,但需要(??)重命名列(因为SQL 不喜欢使用“.”的列名)。但从概念上讲,它更简单。

weather    <- structure(list(weather.station = c("A", "A"), date = c("11/30/2013 ", "12/01/2013 "), temp = c(30, 28), HDD = c(35L, 37L)), .Names = c("weather.station", "date", "temp", "HDD"), class = "data.frame", row.names = c(NA, -2L))
home.bills <- structure(list(home.id = c(1, 1, 2, 2), start.date = c(" 11/15/2013 ", " 12/15/2013 ", " 11/18/2013 ", " 12/16/2013 "), end.date = c(" 12/14/2013 ", " 1/14/2014  ", " 12/15/2013 ", " 1/13/2014  "), electric.usage = c(80, 85, 60, 57), weather.station = c("A", "A", "A", "A")), .Names = c("home.id", "start.date", "end.date", "electric.usage", "weather.station"), class = "data.frame", row.names = c(NA, -4L))

# dates need to be Dates, not character
weather$date <- as.Date(weather$date,format="%m/%d/%Y")
home.bills$start.date <- as.Date(home.bills$start.date,format="%m/%d/%Y")
home.bills$end.date   <- as.Date(home.bills$end.date,format="%m/%d/%Y")

# sqldf does not like "." in column names!!!
colnames(weather) <- gsub(".","_",colnames(weather),fixed=T)
colnames(home.bills) <- gsub(".","_",colnames(home.bills),fixed=T)

library(sqldf)
sqldf("select a.*, avg(temp) as mean_temp, sum(HDD) as sum_HDD
      from [home.bills] a join weather b 
      on b.date>=a.start_date and b.date<=a.end_date 
        and a.weather_station=b.weather_station
      group by home_id, start_date, end_date")
#   home_id start_date   end_date electric_usage weather_station mean_temp sum_HDD
# 1       1 2013-11-15 2013-12-14             80               A        29      72
# 2       2 2013-11-18 2013-12-15             60               A        29      72

第二个使用data.table 包中的foverlaps(...) 功能。这是非常强大且非常快速的。请注意,此解决方案与 @akrun 几个小时前发布的解决方案几乎相同,然后被删除(我很想知道为什么??)。

# data.table solution
weather    <- structure(list(weather.station = c("A", "A"), date = c("11/30/2013 ", "12/01/2013 "), temp = c(30, 28), HDD = c(35L, 37L)), .Names = c("weather.station", "date", "temp", "HDD"), class = "data.frame", row.names = c(NA, -2L))
home.bills <- structure(list(home.id = c(1, 1, 2, 2), start.date = c(" 11/15/2013 ", " 12/15/2013 ", " 11/18/2013 ", " 12/16/2013 "), end.date = c(" 12/14/2013 ", " 1/14/2014  ", " 12/15/2013 ", " 1/13/2014  "), electric.usage = c(80, 85, 60, 57), weather.station = c("A", "A", "A", "A")), .Names = c("home.id", "start.date", "end.date", "electric.usage", "weather.station"), class = "data.frame", row.names = c(NA, -4L))

library(data.table) >= 1.9.4
# convert to data.tables and convert date to Date
setDT(weather)[,date:=as.Date(date,format="%m/%d/%Y")]
setDT(home.bills)[,(2:3):=lapply(.SD,as.Date,format="%m/%d/%Y"),.SDcols=2:3]
# need start.date and end.date in weather data.table (both = date)
weather[,c("start.date","end.date"):=list(date,date)]
setkey(home.bills,weather.station,start.date,end.date)
# calaculate overlaps
result <- foverlaps(weather,home.bills,nomatch=0)
# aggregate
result[,list(mean.temp=mean(temp),sum.HDD=sum(HDD)),
       by=list(home.id,start.date,end.date,electric.usage,weather.station)]
#    home.id start.date   end.date electric.usage weather.station mean.temp sum.HDD
# 1:       1 2013-11-15 2013-12-14             80               A        29      72
# 2:       2 2013-11-18 2013-12-15             60               A        29      72

【讨论】:

  • sqldf 本身不会用点转换列名。如果您将 sqldf 与 SQLite 以外的任何数据库一起使用,则名称不会被转换。是 RSQLite 做到了这一点,但自从 RSQLite 1.0 RSQLite 不再这样做了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多