#r #date #loops
#r #Дата #циклы
Вопрос:
У меня есть данные о погоде, которые записывались каждый час, и данные о местоположении (X, Y), которые записывались каждые 4 часа. Я хочу знать, какая температура была в местоположении X, Y. Данные о погоде поступают не совсем в одно и то же время. Итак, я написал этот цикл для каждого местоположения, чтобы сканировать данные о погоде в поисках «ближайшего» по дате / ВРЕМЕНИ и извлекать данные за это время. Проблема в том, как я это написал, для местоположения # 2 он просматривает данные о погоде, но не позволяет присваивать информацию о ближайшем времени, которая была назначена для местоположения # 1. Допустим, местоположения № 1 и 2 взяты в течение 10 минут в 18:00 и 18: 10 вечера, ближайшее погодное время — 18:00. Я не могу заставить его разрешить данные о погоде в 18:00 в качестве опции. Я вроде как настроил это так, потому что в моем наборе данных о местоположении 200 местоположений (скажем, через 3 месяца), я не хочу, чтобы это начиналось с момента 0 из данных о погоде, когда я знаю, что самые близкие данные о погоде были только что рассчитаны для последнего местоположения, и в этом наборе данных тоже 3 месяца. Ниже приведены некоторые примеры данных и мой код. Я не знаю, имеет ли это смысл.
<h6>####Location data</h6>
<p>X Y DateTime <br />
1 2 4/2/2003 18:01:01
3 2 4/4/2003 17:01:33
2 3 4/6/2003 16:03:07
5 6 4/8/2003 15:03:08
3 7 4/10/2003 14:03:06
4 5 4/2/2003 13:02:00
4 5 4/4/2003 12:14:43
4 3 4/6/2003 11:00:56
3 5 4/8/2003 10:02:06</p>
<h2>2 4 4/10/2003 9:02:19</h2>
<p>Weather Data
DateTime WndSp WndDir Hgt
4/2/2003 17:41:00 8.17 102.86 3462.43
4/2/2003 20:00:00 6.70 106.00 17661.00
4/2/2003 10:41:00 6.18 106.00 22000.00
4/2/2003 11:41:00 5.78 106.00 22000.00
4/2/2003 12:41:00 5.48 104.00 22000.00
4/4/2003 17:53:00 7.96 104.29 6541.00
4/4/2003 20:53:00 6.60 106.00 22000.00
4/4/2003 19:41:00 7.82 105.00 7555.00
4/4/2003 7:41:00 6.62 105.00 14767.50
4/4/2003 8:41:00 6.70 106.00 17661.00
4/4/2003 9:41:00 6.60 106.00 22000.00
4/5/2003 20:41:00 7.38 106.67 11156.67
4/6/2003 18:07:00 7.82 105.00 7555.00
4/6/2003 21:53:00 6.18 106.00 22000.00
4/6/2003 21:41:00 6.62 105.00 14767.50
4/6/2003 4:41:00 7.96 104.29 6541.00
4/6/2003 5:41:00 7.82 105.00 7555.00
4/6/2003 6:41:00 7.38 106.67 11156.67
4/8/2003 18:53:00 7.38 106.67 11156.67
4/8/2003 22:53:00 5.78 106.00 22000.00
4/8/2003 1:41:00 5.78 106.00 22000.00
4/8/2003 2:41:00 5.48 104.00 22000.00
4/8/2003 3:41:00 8.17 102.86 3462.43
4/10/2003 19:53:00 6.62 105.00 14767.50
4/10/2003 23:53:00 5.48 104.00 22000.00
4/10/2003 22:41:00 6.70 106.00 17661.00
4/10/2003 23:41:00 6.60 106.00 22000.00
4/10/2003 0:41:00 6.18 106.00 22000.00
4/11/2003 17:41:00 8.17 102.86 3462.43</p>
<h2>4/12/2003 18:41:00 7.96 104.29 6541.0</h2>
.
weathrow = 1
for (i in 1:nrow(SortLoc)) {
t = 0
while (t < 1) {
timedif1 = difftime(SortLoc$DateTime[i], SortWeath$DateTime[weathrow], units="auto")
timedif2 = difftime(SortLoc$DateTime[i], SortWeath$DateTime[weathrow 1], units="auto")
if (timedif2 < 0) {
if (abs(timedif1) < abs(timedif2)) {
SortLoc$WndSp[i]=SortWeath$WndSp[weathrow]
SortLoc$WndDir[i]=SortWeath$WndDir[weathrow]
SortLoc$Hgt[i]=SortWeath$Hgt[weathrow]
} else {
SortLoc$WndSp[i]=SortWeath$WndSp[weathrow 1]
SortLoc$WndDir[i]=SortWeath$WndDir[weathrow 1]
SortLoc$Hgt[i]=SortWeath$Hgt[weathrow 1]
}
t = 1
}
if (abs(SortLoc$DateTime[i] - SortLoc$DateTime[i 1] < 50)) {
weathrow=weathrow
} else {
weathrow = weathrow 1
#if(weathrow = nrow(SortWeath)){t=1}
}
} #end while
}
Комментарии:
1. Если это вопрос R, не могли бы вы предоставить некоторые образцы данных в простом в использовании формате R? т.е. dput (object) небольшого объема будет достаточно.
2. Над кодом R находится небольшой набор данных. Я не уверен, что означает dput (object), поскольку я изучаю по ходу работы.
3. Если вы поместите объект (переменную) в dput (object), он выведет что-то, что другие могут использовать для копирования и вставки части ваших данных.
Ответ №1:
Вы могли бы использовать findInterval
функцию для поиска ближайшего значения:
# example data:
x <- rnorm(120000)
y <- rnorm(71000)
y <- sort(y) # second vector must be sorted
id <- findInterval(x, y, all.inside=TRUE) # finds position of last y smaller then x
id_min <- ifelse(abs(x-y[id])<abs(x-y[id 1]), id, id 1) # to find nearest
В вашем случае могут потребоваться некоторые as.numeric
.
# assumed that SortWeath is sorted, if not then SortWeath <- SortWeath[order(SortWeath$DateTime),]
x <- as.numeric(SortLoc$DateTime)
y <- as.numeric(SortWeath$DateTime)
id <- findInterval(x, y, all.inside=TRUE)
id_min <- ifelse(abs(x-y[id])<abs(x-y[id 1]), id, id 1)
SortLoc$WndSp <- SortWeath$WndSp[id_min]
SortLoc$WndDir <- SortWeath$WndDir[id_min]
SortLoc$Hgt <- SortWeath$Hgt[id_min]
Некоторое дополнение: вы никогда не должны, АБСОЛЮТНО НОВЫЕ, добавлять значения в data.frame
в for-loop. Проверьте это сравнение:
N=1000
x <- numeric(N)
X <- data.frame(x=x)
require(rbenchmark)
benchmark(
vector = {for (i in 1:N) x[i]<-1},
data.frame = {for (i in 1:N) X$x[i]<-1}
)
# test replications elapsed relative
# 2 data.frame 100 4.32 22.74
# 1 vector 100 0.19 1.00
data.frame
версия более чем в 20 раз медленнее, и чем больше строк она содержит, тем разница больше.
Итак, если вы измените свой скрипт и сначала инициализируете результирующие векторы:
tmp_WndSp <- tmp_WndDir <- tmp_Hg <- rep(NA, nrow(SortLoc))
затем обновите значения в цикле
tmp_WndSp[i] <- SortWeath$WndSp[weathrow 1]
# and so on...
и в конце (вне цикла) обновите соответствующие столбцы:
SortLoc$WndSp <- tmp_WndSp
SortLoc$WndDir <- tmp_WndDir
SortLoc$Hgt <- tmp_Hgt
Это должно выполняться намного быстрее.
Комментарии:
1. большое вам спасибо! это отлично работает. и нет необходимости в цикле! теперь, чтобы протестировать это полностью!
Ответ №2:
Вот пример одной стратегии, которую вы могли бы использовать. При этом время погоды просматривается одно за другим, затем принимается абсолютное значение разницы между этим временем и временем каждого местоположения, затем фиксируется наименьшая разница во времени. Это решает вашу проблему «смотреть вперед / оглядываться назад». Ваш набор данных кажется достаточно маленьким, чтобы переход к полувекторизованному решению обеспечил вам необходимый прирост скорости, но если нет, то его должно быть относительно просто добавить в движущееся окно, которое передает только некоторые / — N наблюдений вокруг последнего loc.match.index.
w <- as.POSIXct(strptime( c("4/2/2003 17:41:00","4/2/2003 20:00:00","4/2/2003 10:41:00","4/2/2003 11:41:00","4/2/2003 12:41:00"),format="%m/%d/%Y %H:%M:%S"))
l <- as.POSIXct(strptime( c("4/2/2003 18:01:01","4/2/2003 17:01:33","4/2/2003 16:03:07","4/2/2003 15:03:08","4/2/2003 14:03:06","4/2/2003 13:02:00"),format="%m/%d/%Y %H:%M:%S"))
window.size <- 5
findClosest <- function(w.i,l) {
which.min(abs(w.i-l))
}
makeWindow <- function(loc.match.index,i,window.size,n) {
win.max <- loc.match.index[i-1] window.size
if(win.max > n) {
win.max <- n
}
win.min <- loc.match.index[i-1] - window.size
if(win.min < 1) {
win.min <- 1
}
return(seq(win.min,win.max))
}
loc.match.index <- integer()
n <- length(w)
# Initialize on whole vector
i <- 1
loc.match.index[i] <- findClosest(w[i],l)
# Continue on window
for(i in seq(2,n)) {
wndw <- makeWindow(loc.match.index,i,window.size,n)
loc.match.index[i] <- findClosest(w[i],l[wndw])
# Add the start of the window back to the index that was returned
loc.match.index[i] <- loc.match.index[i] min(wndw)-1
}
> loc.match.index
[1] 1 1 5 5 5
Здесь все еще есть области, которые можно было бы сделать более эффективными, но это должно быть достаточно быстрым, учитывая, что сравнения векторизованы и окно можно настроить.
Комментарии:
1. Итак, мой набор данных состоит из 120 000 местоположений, и моя погода была собрана за 5 лет, поэтому 71 000 данных о погоде. Ранее я написал скрипт для выполнения того, что, по-моему, вы описали, но для обработки потребовалось 8 дней и подключение 1 компьютера для этого. Для пункта 1 я вычислил разницу в дате и времени для всех погодных данных (71 000 различий), а затем нашел минимальное значение. Теперь проделайте это 120 000 раз. Таким образом, идея окна. Мне не нужно выполнять обратное вычисление, и мне не нужно выполнять поиск до конца. Итак, ваш совет по поводу окна … не могли бы вы объяснить это немного подробнее?
2. Я попытался запустить предоставленный вами небольшой скрипт с дополнительными данными о погоде и выдал ошибку, в которой указывалось, что data.frames должны быть одинакового размера. В моей текущей попытке было больше погодных точек, чем местоположений, но в окончательной версии будет больше точек местоположения, чем погоды. В любом случае…
3. @Kerry: Добавлено окно для вас.
4. @Kerry: Я подтвердил, что это работает с разными длинами векторов на моем компьютере. Работает ли это, когда вы копируете и вставляете их? Я подозреваю, что при переходе от моего упрощенного решения к вашему решению на основе data.frame вы допустили ошибку. Возможно, опубликовать свой код? Я бы поработал с data.frames, если бы вы предоставили
dput()
выходные данные … для дальнейшего использования,dput
действительно упрощает работу для всех.