Как эффективно подмножить несколько фреймов данных в «R»?

У меня есть большой файл NetCDF с данными об атмосферных частицах PM10. Вы можете загрузить здесь. проблема.

Этот файл 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 столбцов матрицы. строка 1 — количество городских объектов, строка 2 — широта, строка 3 — долгота.]

ВРЕМЯ :: данные были собраны с 1 марта 2012 г., 01:00 по май 2012 г. [кодировка «время» — ГГГГММДДЧЧ]

PM10 :: почасовая концентрация твердых частиц измеряется на каждой станции каждого объекта

Из этого файла ncdf я уже выделил значения PM10 только для городских объектов на 1 марта 2012 г., 1:00 (2012030101). Здесь, как вы знаете, TMSID — это идентификатор всего сайта, но я хотел создать подмножество только для городских сайтов (а не для сельских, дорожных и т. д.), поэтому я сопоставил только городской идентификатор из TMSID для 1 марта 2012 года, 1:00. Это означает, что у меня есть подмножество только данных PM10 за 1 час за 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

В последних двух строках вышеприведенного кода у меня есть подмножество значений 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:00 ночи. Теперь я хочу проделать ту же работу за каждый час с 1 марта до 7 марта. Это означает, что я хочу получить (7 * 24) кадр данных. Как я могу сделать это эффективно?

Пожалуйста, спросите меня, есть ли у вас дополнительные вопросы. Заранее спасибо.


person Orpheus    schedule 16.07.2015    source источник
comment
так что единственное, что вам нужно сделать, это начать со строки urban311 и просто изменить time%in%2012030101 на time%in%2012030102, time%in%2012030103 и т. д.? оберните эти строки в функцию, верните набор данных и используйте lapply для получения списка кадров данных за каждый час. это сработает?   -  person rawr    schedule 16.07.2015
comment
@rawr, я очень новичок в R. поэтому, вероятно, я не могу понять вашу мысль. Но я могу выполнить эту работу, вставив один и тот же код (7 * 24) раз и просто заменив время, например 20120302, 20120303 и т. Д., Но это становится таким длинным и неуклюжим.   -  person Orpheus    schedule 16.07.2015
comment
Я настоятельно настоятельно рекомендую использовать пакет raster. Это потрясающе. В этом случае все было бы намного проще. Его документация превосходна. Кроме того, рассмотрите возможность использования ncdf4 вместо ncdf.   -  person AF7    schedule 17.07.2015


Ответы (2)


Здесь нет необходимости использовать 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'))

Затем выясните, какие индексы являются городскими идентификаторами и имеют правильное время:

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, как и раньше. Обратите внимание, что поскольку каждый идентификатор появляется 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 по мере необходимости.

person mathematical.coffee    schedule 16.07.2015
comment
я понимаю, что если я хочу сделать (7 * 24) другой набор данных / кадр данных, мне нужно копировать-вставлять subset(x, time==2012030101) для (7 * 24) раз за каждый час, заменяя время. я прав? не очень ли длинно? Я не знаю, возможно ли сделать (7 * 24) другой набор данных немного короче или нет. - person Orpheus; 16.07.2015
comment
Другой вопрос, Вы пишете код типа x <- data.frame(ID=as.vector(tmsid[i]), time=as.vector(time[i]), PM10=as.vector(pm10[i])) Но даже если я напишу таким образом x<-data.frame(ID=tmsid[i], Time=time[i], PM10=pm10[i]), то у меня получится то же самое. почему это происходит? - person Orpheus; 16.07.2015
comment
Первый вопрос: моя строка lapply делает все это за вас, где каждый элемент списка является одним из ваших фреймов данных. Вы не хотите называть их все по отдельности, иначе вам придется печатать каждую строку, как вы упомянули; следовательно, я держу их в списке. Второй вопрос: нет никакой реальной разницы между использованием as.vector или нет, я просто заметил, что если вы этого не сделаете, class(x$ID) и т. д. будет «массивом», а не числовым вектором, как в большинстве фреймов данных. Я не знаю, почему это так, и я не думаю, что это будет иметь значение, если честно. - person mathematical.coffee; 17.07.2015
comment
Вы имеете в виду, что если я хочу (7 * 24) отдельного объекта фреймов данных, мне нужно написать subset(x, time==2012030101) этот код (7 * 24) раз? или есть какой-либо способ сделать цикл, с помощью которого я могу сделать (7 * 24) объект кадра данных на 1 или 2 строки? извините, я новичок в р. потому что я должен рисовать полувариограмму для каждого часа данных. Если у меня есть список (7 * 24) фреймов данных, то как я могу работать с одним фреймом данных из этого списка? - person Orpheus; 17.07.2015
comment
Нет, вам не нужно писать subset 168 раз, я уже упоминал, как вы можете использовать lapply, чтобы сделать все сразу. Если вы хотите работать с одним фреймом данных из этого списка, используйте подмножество списка, чтобы получить этот фрейм данных, или цикл/прилипание для работы с каждым из фреймов данных. - person mathematical.coffee; 17.07.2015
comment
@mathematival.coffe, я нашел проблему в вашем ответе. В первой строке вы написали seq(as.POSIXct('2012-03-01 01:00'), as.POSIXct('2012-03-07 00:00'). после преобразования в числовую форму вывод будет выглядеть как 2012030101,2012030102....2012030323,2012030100. Но в моем наборе данных время уже числовое, и вместо 2012030100 стоит 2012030124. Итак, в 4-й строке, когда вы написали time=as.vector(time[i]), мы потеряем все значение 2012030124! есть ли способ сделать 2012030124 с помощью POSIXct? - person Orpheus; 19.08.2015

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) кадров данных.

person Orpheus    schedule 16.07.2015