如何在 'R' 中有效地对多个数据帧进行子集化?
How to subset multiple data frame efficiently in 'R'?
我有一个很大的 '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为站点数(包括城市站点、农村站点、道路、背景等)
urban :: 城市站点数 [urban 是 3 行 250 列的矩阵。第1行是城市站点数,第2行是纬度,第3行是经度。]
TIME :: 数据收集自 2012 年 3 月 1 日 1.00 a.m。到 2012 年 5 月 ['time' 的编码是 YYYYMMDDHH]
PM10 :: 在每个站点的每个站点测量的每小时颗粒物浓度
从这个 ncdf 文件中,我已经对 2012 年 3 月 1 日 1 a.m 的城市站点的 PM10 值进行了子集化。 (2012030101)。在这里,如您所知,TMSID 是所有站点的 ID,但我只想为城市站点(而不是农村、道路等)子集,所以我只匹配 2012 年 3 月 1 日 TMSID 的城市 ID,1 a.m .这意味着我只对城市站点 3 月 1 日的 1 小时 PM10 数据进行了子集化。我使用了以下代码:
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
如您所知,这是仅 3 月 1 日 1.00 a.m 的数据框。现在我想从 3 月 1 日到 3 月 7 日每小时做同样的工作。这意味着我想获得 (7*24) 数据框。我怎样才能有效地做到这一点?
请问我是否还有其他问题。提前致谢。
这里不用lapply
。
此外,与其获得 7*24 数据帧,不如使用包含所有日期的 one 数据帧更有意义,然后您可以根据需要对其进行子集化。
这一切都发生了,而不是你的 urban311
东西。
首先列出我们要保留的所有 time
s:
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)
是您的 urban311
。 x
里面有你想要的所有不同日期时间。
然后如果你想添加 LAT
和 LON
,像以前一样使用 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
。
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)个数据框
我有一个很大的 '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为站点数(包括城市站点、农村站点、道路、背景等)
urban :: 城市站点数 [urban 是 3 行 250 列的矩阵。第1行是城市站点数,第2行是纬度,第3行是经度。]
TIME :: 数据收集自 2012 年 3 月 1 日 1.00 a.m。到 2012 年 5 月 ['time' 的编码是 YYYYMMDDHH]
PM10 :: 在每个站点的每个站点测量的每小时颗粒物浓度
从这个 ncdf 文件中,我已经对 2012 年 3 月 1 日 1 a.m 的城市站点的 PM10 值进行了子集化。 (2012030101)。在这里,如您所知,TMSID 是所有站点的 ID,但我只想为城市站点(而不是农村、道路等)子集,所以我只匹配 2012 年 3 月 1 日 TMSID 的城市 ID,1 a.m .这意味着我只对城市站点 3 月 1 日的 1 小时 PM10 数据进行了子集化。我使用了以下代码:
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
如您所知,这是仅 3 月 1 日 1.00 a.m 的数据框。现在我想从 3 月 1 日到 3 月 7 日每小时做同样的工作。这意味着我想获得 (7*24) 数据框。我怎样才能有效地做到这一点?
请问我是否还有其他问题。提前致谢。
这里不用lapply
。
此外,与其获得 7*24 数据帧,不如使用包含所有日期的 one 数据帧更有意义,然后您可以根据需要对其进行子集化。
这一切都发生了,而不是你的 urban311
东西。
首先列出我们要保留的所有 time
s:
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)
是您的 urban311
。 x
里面有你想要的所有不同日期时间。
然后如果你想添加 LAT
和 LON
,像以前一样使用 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
。
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)个数据框