如何在' R'中高效地对多个数据帧进行子集化

时间:2015-07-16 03:03:20

标签: r subset lapply netcdf

我有一个大型的NetCDF'大气PM10数据文件。您可以从here下载。我正在解释有关我的问题的详细信息。

这个ncdf文件有8个这样的变量。

[1] "file ~/Downloads/2012_03_05_PM10_surface.nc has 8 dimensions:"
[1] "data_num   Size: 683016"
[1] "ncl1   Size: 683016"
[1] "obsnum_urban   Size: 250"
[1] "ID_LAT_LON   Size: 3"
[1] "obsnum_road   Size: 33"
[1] "obsnum_background   Size: 5"
[1] "obsnum_rural   Size: 16"
[1] "ncl7   Size: 683016"
[1] "------------------------"
[1] "file ~/Downloads/2012_03_05_PM10_surface.nc has 8 variables:"
[1] "int TMSID[data_num]  Longname:TMSID Missval:NA"
[1] "int TIME[ncl1]  Longname:TIME Missval:NA"
[1] "float PM10[data_num]  Longname:PM10 Missval:1e+30"
[1] "float urban[ID_LAT_LON,obsnum_urban]  Longname:urban Missval:1e+30"
[1] "float road[ID_LAT_LON,obsnum_road]  Longname:road Missval:1e+30"
[1] "float background[ID_LAT_LON,obsnum_background]  Longname:background Missval:1e+30"
[1] "float rural[ID_LAT_LON,obsnum_rural]  Longname:rural Missval:1e+30"
[1] "int TMS_JULIAN[ncl7]  Longname:TMS_JULIAN Missval:NA"

在这里,我的兴趣只有4个变量。他们是:

TIMSID是站点数量(包括城市站点,乡村站点,道路,背景等)

城市::城市遗址数量[城市是3排250列矩阵。 row1是城市站点的数量,row2是latidude,第3行是经度。]

TIME ::数据是从2012年3月1日,凌晨1点到2012年5月收集的[编码时间'是YYYYMMDDHH]

PM10 ::每个站点的每个站点测量的每小时颗粒物浓度

从这个ncdf文件中,我已经为2012年3月1日凌晨1点(2012030101)的城市网站分配了PM10值。在这里,如你所知,TMSID是所有网站的id,但我想仅为城市网站(不是农村,公路等)的子集,所以我只匹配TMSID的城市id为2012年3月1日,凌晨1点这意味着我有对于城市站点仅1小时PM10数据的1个子集。我使用了以下代码:

library(ncdf)
nc<-open.ncdf("2012_03_05_PM10_surface.nc")
print(nc)

urban<-get.var.ncdf(nc,"urban")
time<-get.var.ncdf(nc,"TIME")
pm10<-get.var.ncdf(nc,"PM10")
tmsid<-get.var.ncdf(nc,"TMSID")
urban<-as.data.frame(t(urban))
colnames(urban)<-c("ID","LAT","LON")

urban311<-lapply(urban$ID,
                 function(x)data.frame(ID=x,time=2012030101,
                                       PM10=pm10[tmsid%in%x &
                                                   time%in%2012030101]))
urban311<-do.call(rbind,urban311)
urban311<-merge(urban311,urban,by="ID")
urban311
urban311<-subset(urban311,select=c("time","ID","LAT","LON","PM10"))

seoul311<-subset(urban311, LAT>=36.8 & LAT <=38 & LON>=126.4 & LON<= 127.3)
rownames(seoul311)<-NULL

在上述代码的最后2行中,根据纬度和经度,我仅针对来自城市站点的特定区域的子集PM10值。最后我得到了这样的数据框架。

              time     ID      LAT      LON PM10
    1   2012030101 111121 37.56464 126.9760   42
    2   2012030101 111123 37.57203 127.0050   37
    .
    .
    .
   106  2012030101 831153 37.49195 126.7533   68
   107  2012030101 831154 37.52662 126.8064   57

如您所知,这是1月1日凌晨1点的数据框。现在我想从3月1日到3月3日每小时做同样的工作。这意味着我想得到(7 * 24)数据帧。我怎样才能有效地做到这一点?

请问我是否还有其他问题。提前谢谢。

2 个答案:

答案 0 :(得分:1)

此处无需使用lapply。 此外,不是获得7 * 24个数据帧,而是拥有包含所有日期的一个数据帧更有意义,然后您可以根据需要对其进行子集化。

这一切都发生了,而不是你的urban311。 首先列出我们要保留的所有time

dts.to.get <- seq(as.POSIXct('2012-03-01 01:00'), as.POSIXct('2012-03-07 00:00'), by='1 hour')
# convert to the 2012030101 numeric format you have
dts.number <- as.numeric(format(dts.to.get, '%Y%m%d%H'))

然后确定哪些指数是城市ID并且有合适的时间:

i <- tmsid %in% urban$ID & time %in% dts.number
x <- data.frame(ID=as.vector(tmsid[i]), time=as.vector(time[i]), PM10=as.vector(pm10[i]))

请注意,subset(x, time==2012030101)是您的urban311x具有您所追求的所有不同日期时间。

然后,如果您希望添加LATLON,请像以前一样使用merge。请注意,由于每个ID出现7 * 64次,因此在您的数据框中复制了168次,因此您最好将它们分开。

x <- merge(x, urban, by='ID')

无需执行额外的subset(urban311, select=c("time", "ID", "LAT", "LON", "PM10")),因为它们是urban311唯一的列。

如果您确实 希望将x分成每个日期小时的一个数据框,那么您可以

lapply(unique(x$time), function (tt) subset(df, time == tt))

获取数据帧列表,但实际上,它不值得。需要年龄,并且根据需要更快到subset

答案 1 :(得分:0)

library(ncdf)
nc<-open.ncdf("2012_03_05_PM10_surface.nc")
print(nc)

urban<-get.var.ncdf(nc,"urban")
time<-get.var.ncdf(nc,"TIME")
pm10<-get.var.ncdf(nc,"PM10")
tmsid<-get.var.ncdf(nc,"TMSID")

urban<-as.data.frame(t(urban))
colnames(urban)<- c("ID","LAT","LON")

dates<-seq(as.POSIXct("2012-03-01:01:00"),
           as.POSIXct("2012-03-08:00:00"), by="1 hour")
dates.numeric <-as.numeric(format(dates, "%Y%m%d%H"))

i<-tmsid %in% urban$ID & time %in% dates.numeric
urban1to7<-data.frame(ID=as.vector(tmsid[i]), 
              time= as.vector(time[i]),
              PM10=as.vector(pm10[i]))
urban1to7<-merge(urban1to7,urban,by="ID")
urban311<-subset(urban1to7, time=2012030101)

#urban sites,seoul area,7 days,every hour
seoul1to7<-subset(urban1to7,LAT>=36.8 & LAT<=38 & LON>=126.4 & LON<=127.3)

# make a list where there is (7*24) data frames
lapply(unique(seoul1to7$time), function(x) subset(seoul1to7, time==x))

通过这种方式,我们可以通过lapply创建一个包含(7 * 24)数据帧的列表。