Как мне найти ближайшую дату к данной дате? - PullRequest
2 голосов
/ 07 марта 2019

Я пытаюсь выяснить, как найти ближайшую дату в 1 объекте зоопарка к заданной дате в другом объекте зоопарка (также можно использовать data.frame). Предположим, у меня есть:

dates.zoo <- zoo(data.frame(val=seq(1:121)), order.by = seq.Date(as.Date('2018-12-01'), as.Date('2019-03-31'), "days"))
monthly.zoo <- zoo(data.frame(val=c(1,2,4)), order.by = c(as.Date('2018-12-14'), as.Date('2019-1-2'), as.Date('2019-2-3')))

Для каждой даты в dates.zoo я хотел бы выровнять ее с ближайшей предыдущей датой в monthly.zoo. (NA, если месячная дата не найдена). Итак, ожидаемый объект data.frame / zoo:

...
2018-12-02   2  NA
...
2018-12-14  14  2018-12-14
2018-12-15  15  2018-12-14
2018-12-16  16  2018-12-14
...
2019-01-01  32  2018-12-14
2019-01-02  33  2019-01-02
2019-01-03  34  2019-01-02
...

ПРИМЕЧАНИЕ: я бы предпочел решение Base-R, но другим было бы интересно посмотреть также

Ответы [ 4 ]

2 голосов
/ 07 марта 2019

Может использоваться скользящее соединение с использованием data.table.См. Также: https://www.r -bloggers.com / creation-data-table-Rolling-Joins /

Также решение, использующее решение base-R

data.table

library(data.table)
dates.df <- data.table(val=seq(1:121), dates = seq.Date(as.Date('2018-12-01'), as.Date('2019-03-31'), "days"))
monthly.df <- data.table(val=c(1,2,4,5), dates = c(as.Date('2018-12-14'), as.Date('2019-1-2'), as.Date('2019-2-3')))

setkeyv(dates.df,"dates")
setkeyv(monthly.df,"dates")

#monthly.df[,nearest:=(dates)][dates.df,roll = 'nearest'] #closest date
monthly.df[,nearest:=(dates)][dates.df,roll = Inf] #Closest _previous_ date

базовое решение R

dates.df <- zoo(data.frame(val=seq(1:121)), order.by = seq.Date(as.Date('2018-12-01'), as.Date('2019-03-31'), "days"))
monthly.df <- zoo(data.frame(val=c(1,2,4)), order.by = c(as.Date('2018-12-14'), as.Date('2019-1-2'), as.Date('2019-2-3')))

dates.df <- data.frame(val=dates.df$val,dates=attributes(dates.df)$index)
monthly.df <- data.frame(val=monthly.df$val,dates=attributes(monthly.df)$index)

min_distances <- as.numeric(dates.df$dates)- matrix(rep(as.numeric(monthly.df$dates),nrow(dates.df)),ncol=length(monthly.df$dates),byrow=T)
min_distances <- as.data.frame(t(min_distances))

closest <- sapply(min_distances,function(x) 
  { 
    w <- which(x==min(x[x>0])); 
    ifelse(length(w)==0,NA,w) 
  })

dates.df$closest_month <- monthly.df$dates[closest]

Результаты: data.table

> monthly.df[,nearest:=(dates)][dates.df,roll = Inf]
     val      dates    nearest i.val
  1:  NA 2018-12-01       <NA>     1
  2:  NA 2018-12-02       <NA>     2
  3:  NA 2018-12-03       <NA>     3
  4:  NA 2018-12-04       <NA>     4
  5:  NA 2018-12-05       <NA>     5
 ---                                
118:   4 2019-03-27 2019-02-03   117
119:   4 2019-03-28 2019-02-03   118
120:   4 2019-03-29 2019-02-03   119
121:   4 2019-03-30 2019-02-03   120
122:   4 2019-03-31 2019-02-03   121

База результатов R

> dates.df[64:69,]
           val      dates closest_month
2019-02-02  64 2019-02-02    2019-01-02
2019-02-03  65 2019-02-03    2019-01-02
2019-02-04  66 2019-02-04    2019-02-03
2019-02-05  67 2019-02-05    2019-02-03
2019-02-06  68 2019-02-06    2019-02-03
2019-02-07  69 2019-02-07    2019-02-03
1 голос
/ 07 марта 2019

Следуя предложению Хенрика использовать findInterval. Мы можем сделать:

interval.idx <- findInterval(index(dates.zoo), index(monthly.zoo))
dates.zoo$month <- ifelse(interval.idx == 0, NA, index(monthly.zoo)[interval.idx]))
1 голос
/ 07 марта 2019

Здесь есть возможность, хотя мне пришлось изменить объект на фрейм данных, чтобы назначить даты индекса зоопарка.Этот код сравнивает месяц, затем год и, наконец, день с критериями, которые меньше или равны дате, с которой сопоставляются.Если нет даты, которая соответствует этому критерию, тогда назначается NA.Эти сравнения были сделаны с помощью пакета lubridate, проверяющего отдельные элементы даты, и затем для логической индексации наилучшего соответствия.

library(zoo)
library(lubridate)

dates.df <- zoo(data.frame(val=seq(1:121)), order.by = seq.Date(as.Date('2018-12-01'), as.Date('2019-03-31'), "days"))
monthly.df <- zoo(data.frame(val=c(1,2,4)), order.by = c(as.Date('2018-12-14'), as.Date('2019-1-2'), as.Date('2019-2-3')))

month_m<-month(monthly.df)
month_d<-month(dates.df)

year_m<-year(monthly.df)
year_d<-year(dates.df)

day_m<-day(monthly.df)
day_d<-day(dates.df)

index<-list()
Index<-list()

for( i in 1:length(monthly.df)){

index[[i]]<-which(month_m[i] == month_d & year_m[i] == year_d
                  & day_d <= day_m[i])

test<-unlist(index[[i]])

   #Assigns NA if no suitable match is found
   if(length(test)==0){
    print("NA")
    Index[[i]]=NA
    }else {
    Index[[i]]<-tail(test, n=1)
    }                      
}

Test<-unlist(Index)
monthly.df_Fin<-as.data.frame(monthly.df)
dates.df_Fin<-as.data.frame(dates.df)
monthly.df_Fin$match<-as.character(row.names(dates.df_Fin)[Test])
monthly.df_Fin$value<-dates.df_Fin[Test,]

> monthly.df_Fin
           val      match value
2018-12-14   1 2018-12-14    14
2019-01-02   2 2019-01-02    33
2019-02-03   4 2019-02-03    65

Скажем, мы изменили значение вне диапазона критерия:

monthly.df <- zoo(data.frame(val=c(1,2,4)), order.by = c(as.Date('2018-12- 
14'), as.Date('2019-1-2'), as.Date('2017-2-3')))

....

#Result
> monthly.df_Fin
           val      match value
2017-02-03   4       <NA>    NA
2018-12-14   1 2018-12-14    14
2019-01-02   2 2019-01-02    33
1 голос
/ 07 марта 2019

Если для каждой даты в dates.df вы хотите получить ближайшую дату в monthly.df, которая меньше заданной даты, а monthly.df отсортировано по дате возрастания, вы можете использовать метод ниже.Он подсчитывает количество строк в monthly.df с индексом меньше заданной даты, что эквивалентно индексу, если mothly.df отсортировано по дате возрастания.Если таких строк 0, индекс изменяется на NA.

inds <- rowSums(outer(index(dates.df), index(monthly.df), `>`))
inds[inds == 0] <- NA
dates.df_monthmatch <- index(monthly.df)[inds]


dates.df_monthmatch
#   [1] NA           NA           NA           NA           NA           NA          
#   [7] NA           NA           NA           NA           NA           NA          
#  [13] NA           NA           "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14"
#  [19] "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14"
#  [25] "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14" "2018-12-14"
#  [31] "2018-12-14" "2018-12-14" "2018-12-14" "2019-01-02" "2019-01-02" "2019-01-02"
#  [37] "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02"
#  [43] "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02"
#  [49] "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02"
#  [55] "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02"
#  [61] "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-01-02" "2019-02-03"
#  [67] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
#  [73] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
#  [79] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
#  [85] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
#  [91] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
#  [97] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
# [103] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
# [109] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
# [115] "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03" "2019-02-03"
# [121] "2019-02-03"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...