2016-06-22 96 views
1

我有纵向的地理编码地址数据和每个地理编码的时间长度。然后我有一系列变量(我只是在这里调用它们),它们给出了每个大地水准面位置的特征。下面这里只是两个例子,但我有数千个。使用dplyr处理日期

id<-c(1,1,1,7,7,7,7) 
geoid<-c(53,45,45,16,18,42) 
start<-c("1/1/2004","10/31/2004","1/1/2005","1/1/2005","6/1/2007","7/2/2007") 
end<-c("10/30/2004","12/31/2004","12/31/2007","5/31/2007","7/1/2007","12/31/2007") 
x<-c(.5,.7,.7,.3,.4,.6) 
dat<-data.frame(id,geoid,x,start,end) 
dat$start<-as.Date(dat$start,format='%m/%d/%Y') 
dat$end<-as.Date(dat$end,format='%m/%d/%Y') 
dat 

    id geoid x  start  end 
    1 53 0.5 2004-01-01 2004-10-30 
    1 45 0.7 2004-10-31 2004-12-31 
    1 45 0.7 2005-01-01 2007-12-31 
    7 16 0.3 2005-01-01 2007-05-31 
    7 18 0.4 2007-06-01 2007-08-01 
    7 42 0.6 2007-08-02 2007-12-31 

我需要每年为单个值来结束(2004年,2005年,2006年,2007年),并为每个个案(1,7)是通过在每个地址的时间长度进行加权。因此,案例1在2004年从大地水准面53移到45,案例7从2007年的大地水准面16移动到18到42。所以我计算每个大地水准面的年份百分比(最终我将乘以x乘以平均值每年得到一个加权平均值)。案例原地踏步整整一年将在每年单独看,计算全年的百分比获得1

#calculate the percentage of year at each address for id 1 
(as.Date("10/31/2004",format='%m/%d/%Y')-as.Date("1/1/2004",format='%m/%d/%Y'))/365.25 
Time difference of 0.8323066 
(as.Date("12/31/2004",format='%m/%d/%Y')-as.Date("10/31/2004",format='%m/%d/%Y'))/365.25 
Time difference of 0.1670089 

#calculate the percentage of year at each address for id 7 
(as.Date("05/31/2007",format='%m/%d/%Y')-as.Date("1/1/2007",format='%m/%d/%Y'))/365.25 
Time difference of 0.4106776 
(as.Date("07/01/2007",format='%m/%d/%Y')-as.Date("06/01/2007",format='%m/%d/%Y'))/365.25 
Time difference of 0.08213552 
(as.Date("12/31/2007",format='%m/%d/%Y')-as.Date("07/02/2007",format='%m/%d/%Y'))/365.25 
Time difference of 0.4982888 

我可以用蛮力做到这一点的重量在该地址度过。然后我会用x值乘以每个权重,并取这一年的平均值 - 这对于数千个案例来说是不合理的。任何有关如何更有效地解决这个问题的想法都会受到重视。似乎它可能适用于dplyr slice,但目前我暂时停止了。关键是每年分离出来。

回答

2

希望这会让你开始。我不确定你想如何处理从startend的时间跨度超过一年或跨越日历年的情况。

library(dplyr) 

dat %>% 
    mutate(fractionOfYear = as.numeric(end - start)/365.25) 
id geoid x  start  end fractionOfYear 
1 1 53 0.5 2004-01-01 2004-10-30  0.82956879 
2 1 45 0.7 2004-10-31 2004-12-31  0.16700890 
3 1 45 0.7 2005-01-01 2007-12-31  2.99520876 
4 7 16 0.3 2005-01-01 2007-05-31  2.40930869 
5 7 18 0.4 2007-06-01 2007-07-01  0.08213552 
6 7 42 0.6 2007-07-02 2007-12-31  0.49828884 
4

正如eipi10提到的,一些数据的跨越一年多。它也与您在时差计算中使用的数据不一致,这些数据都在同一年内。

假设你开始和结束日期实际上是在同一年,你可以这样做以下:

foo <- dat %>% 
     mutate(start_year=year(dat$start), 
       end_year=year(dat$end), 
       same_year=(start_year==end_year), 
       year_frac=as.numeric(dat$end - dat$start)/365.25, 
       wtd_x = year_frac * x) 

这给了你:

id geoid x  start  end start_year end_year same_year year_frac  wtd_x 
1 1 53 0.5 2004-01-01 2004-10-31  2004  2004  TRUE 0.83230664 0.41615332 
2 1 45 0.7 2004-10-31 2004-12-31  2004  2004  TRUE 0.16700890 0.11690623 
3 1 45 0.7 2005-01-01 2007-12-31  2005  2007  FALSE 2.99520876 2.09664613 
4 7 16 0.3 2007-01-01 2007-05-31  2007  2007  TRUE 0.41067762 0.12320329 
5 7 18 0.4 2007-06-01 2007-07-01  2007  2007  TRUE 0.08213552 0.03285421 
6 7 42 0.6 2007-07-02 2007-12-31  2007  2007  TRUE 0.49828884 0.29897331 

然后,您可以组总结使用的数据:

bar <- foo %>% 
    group_by(start_year, id) %>% 
summarise(sum(wtd_x)) 

给你答案:

start_year id  sum(wtd_x) 
    (dbl) (dbl)   (dfft) 
1  2004  1 0.5330595 days 
2  2005  1 2.0966461 days 
3  2007  7 0.4550308 days 
+0

这实际上是我试图得到的确切问题。我有数据重叠的年份,但每个年份都需要一个衡量标准。这是我无法弄清楚如何从我的数据中推断出来的部分 – swhusky

+0

当您将它们拆分为单独的年份时,您是否关心列id,大地水准面和x具有相同的值? –

-1

我能找到一些本地帮助,使我们得到了一个简单的功能。我们仍然坚持如何使用日期应用,但总体上处理它。

#made up sample address data 
id<-c(1,1,1,7,7,7) 
geoid<-c(53,45,45,16,18,42) 
start<-c("1/31/2004","10/31/2004","1/1/2005","1/1/2005","6/1/2007","7/2/2007") 
end<-c("10/30/2004","12/31/2004","12/31/2007","5/31/2007","7/1/2007","12/31/2007") 

dat <- data.frame(id,geoid,start,end) 

#format addresses 
dat$start<-as.Date(dat$start,format='%m/%d/%Y') 
dat$end<-as.Date(dat$end,format='%m/%d/%Y') 

#function to create proportion of time at each address 
prop_time <- function(drange, year){ 

    start <- drange[[1]]; end <- drange[[2]] 

    #start year and end year 
    syear <- as.numeric(format(start,'%Y')) 
    eyear <- as.numeric(format(end,'%Y')) 

    #select only those dates that are within the same year 
    if(syear<=year & year<=eyear){ 

    byear <- as.Date(paste("1/1", sep="/", year), format='%m/%d/%Y') 
    eyear <- as.Date(paste("12/31", sep="/", year), format='%m/%d/%Y') 

    astart <- max(byear, start) 
    aend <- min(eyear, end) 

    prop <- as.numeric((aend - astart))/as.numeric((eyear - byear)) 

    } else prop <- 0 #if no proportion within same year calculated then gets 0 

    prop 

} 

#a second function to apply prop_time to multiple cases 
prop_apply <- function(dat_times, year){ 

    out <- NULL 

    for(i in 1:dim(dat_times)[1]){ 
    out <- rbind(out,prop_time(dat_times[i,], year)) 
    } 

    out 

} 


#create new data frame to populate years 
dat <- data.frame(dat, y2004=0, y2005=0, y2006=0, y2007=0) 
dat_times <- dat[,c("start", "end")] 

#run prop_apply in a loop across cases and selected years 
for(j in 2004:2007){ 

    newdate <- paste("y", j, sep="") 
    dat[,newdate] <- prop_apply(dat_times, j) 

} 
+0

在循环中增加一个对象在R. – Frank

+0

中是一个糟糕的主意,在这种情况下你会提出什么其他策略? – swhusky

+0

我还没有仔细阅读你的代码,知道为什么你认为循环中的'rbind'在这里很有用,所以我不知道最好的方法。既然你让'prop'的值为零,我猜你的函数是标量值的,在这种情况下'mapply'可能适合你。通常的参考文献是本书第2章简短的内容,可能对您有所帮助。 – Frank