2016-06-11 44 views
2

我有一个问题,我希望有人可以帮助我。这基本上是数据处理。我有一个由10列,“id”和3组类似变量,“type”,“startdate”和“enddate”组成的大数据集。一个例子可以在下面看到。R:如何根据属性值(日期)逐行进行组排序?

id type1 startdate1 enddate1 type2 startdate2 enddate2 type3 startdate3 
1 1  A 2006-08-20 2006-12-06  W 2006-08-01 2007-08-29  P 2007-08-18 
2 2  A 2006-01-05 2007-07-02 NA   NA   NA  Q 2008-01-15 

    enddate3 
1 2007-09-27 
2 2008-02-07 

我想获得以下清洗和分类数据集:根据“开始日期”的每一行/观测

id type1 startdate1 enddate1 type2 startdate2 enddate2 type3 startdate3 
1 1  W 2006-08-01 2007-08-29  A 2006-08-20 2006-12-06  P 2007-08-18 
2 2  A 2006-01-05 2007-07-02  Q 2008-01-15 2008-02-07 NA   NA 

enddate3 
1 2007-09-27 
2 NA    

我想按升序进行排序。因此,对于第1行,由于与第一组的“开始日期”(2006-08-20)相比,第二组或一组变量具有较早的“开始日期”(2006-08-01),因此我会将其置于第一组位置。

至于第2行,我想推动所有的NAs到最后。

关于如何有效地做到这一点的任何提示?

我应该将数据类型“startdate”和“enddate”转换为数字吗?如果我应该,我该如何处理“不适用”?

是否明智地将paste()函数应用于(type,startdate,enddate)所有3组?

感谢任何帮助!先谢谢你!

回答

1

下面是使用dplyrtidyr的解决方案,它依赖于将数据集转换为长格式,按需要重新排序,然后转换回宽格式。转换为长格式将强制值更改为character,因此需要重新应用列类型。

library(tidyr) 
library(dplyr) 

df <- read.table(header = TRUE, text = " 
id type1 startdate1 enddate1 type2 startdate2 enddate2 type3 startdate3 enddate3 
1  A 2006-08-20 2006-12-06  W 2006-08-01 2007-08-29  P 2007-08-18 2007-09-27 
2  A 2006-01-05 2007-07-02 NA   NA   NA  Q 2008-01-15 2008-02-07 
") 

df %>% 
    gather(key, value, -id) %>% # convert to long format 
    extract(key, c("var", "seq"), "(.*)(\\d)") %>% # extract sequence number 
    spread(var, value) %>% # spread to wide format by id and sequence 
    group_by(id) %>% 
    arrange(startdate) %>% # sort seq by startdate in id groups 
    mutate(seq = 1:n()) %>% # calculate new sequence order 
    gather(key, value, -id, -seq) %>% # convert to long format 
    transmute(var = paste0(key, seq), value) %>% # generate wide format names 
    spread(var, value) %>% # spread to back to wide format 
    select(one_of(names(df))) %>% # restore original column order 
    mutate_each("as.Date", one_of(grep("date", names(df), value = TRUE))) 
     # reapply date type to original date variables 

#  Source: local data frame [2 x 10] 
#  Groups: id [2] 
#  
#   id type1 startdate1 enddate1 type2 startdate2 enddate2 type3 startdate3 enddate3 
#  (int) (chr)  (date)  (date) (chr)  (date)  (date) (chr)  (date)  (date) 
#  1  1  W 2006-08-01 2007-08-29  A 2006-08-20 2006-12-06  P 2007-08-18 2007-09-27 
#  2  2  A 2006-01-05 2007-07-02  Q 2008-01-15 2008-02-07 NA  <NA>  <NA> 
1

我们可以使用plyr包中的rbind.fill。现在,该功能足够智能,可以根据列名进行组合 - 我们不需要这样做。为了向每一行推进观察,我们删除NA,然后将原始数据帧的名称应用到新矢量。

library(plyr) 

df <- data.frame("obs" = seq(3), 
       type1 = c(2,2,NA),date1 = c("date11","date21",NA), 
       type2 = c(3,NA,5),date2 = c("date12",NA,"date31"), 
       type3 = c(4,3,1), date3 = c("date13","date22","date32"), 
       type4 = c(4,4,NA),date4 = c("date14","date23",NA)) 
df 
# obs type1 date1 type2 date2 type3 date3 type4 date4 
# 1 1  2 date11  3 date12  4 date13  4 date14 
# 2 2  2 date21 NA <NA>  3 date22  4 date23 
# 3 3 NA <NA>  5 date31  1 date32 NA <NA> 

newdf <- sapply(1:nrow(df), function(i){ 
    newrow <- (df[i,!is.na(df[i,])])    ## Remove NA's 
    names(newrow) <- names(df)[1:length(newrow)] ## Apply names 

    newrow          ## Output 
}) 

rbind.fill(newdf) 
# obs type1 date1 type2 date2 type3 date3 type4 date4 
# 1 1  2 date11  3 date12  4 date13  4 date14 
# 2 2  2 date21  3 date22  4 date23 NA <NA> 
# 3 3  5 date31  1 date32 NA <NA> NA <NA> 

注意:此代码只工作,如果type和日期,走到一起作为既观察和NA的。

+0

我*,你要推依赖于日期JUST *锯。我认为你基本上是在问两个问题 - 1):如何推动和2):如何排序。我只回答了第一个问题。 – Therkel

+0

非常感谢!这看起来非常有用,因为我的数据集非常稀少,而且我确实需要将NA推向右侧。 – HNSKD

2

相同的方法,米克马尔蒂拉但没有使用非标准库:

> ## use vectors of class Date 
> df[c(3,4,6,7,9,10)] <- lapply(df[c(3,4,6,7,9,10)], as.Date) 

> ## reshape to long format 
> df.1 <- reshape(df, idvar=1, 
+     varying=list(c(2,5,8), c(3,6,9), c(4,7,10)), 
+     v.names=c('type', 'startdate', 'enddate'), 
+     times=c(1,2,3), timevar='group', direction='long') 
> df.1 
#  id group type startdate enddate 
# 1.1 1  1 A 2006-08-20 2006-12-06 
# 2.1 2  1 A 2006-01-05 2007-07-02 
# 1.2 1  2 W 2006-08-01 2007-08-29 
# 2.2 2  2 <NA>  <NA>  <NA> 
# 1.3 1  3 P 2007-08-18 2007-09-27 
# 2.3 2  3 Q 2008-01-15 2008-02-07 

> ## reset group variable according to startdate 
> df.1$group <- with(df.1, unsplit(lapply(split(startdate, id), order), id)) 
> df.1 
#  id group type startdate enddate 
# 1.1 1  2 A 2006-08-20 2006-12-06 
# 2.1 2  1 A 2006-01-05 2007-07-02 
# 1.2 1  1 W 2006-08-01 2007-08-29 
# 2.2 2  3 <NA>  <NA>  <NA> 
# 1.3 1  3 P 2007-08-18 2007-09-27 
# 2.3 2  2 Q 2008-01-15 2008-02-07 

> ## back to wide format 
> df.2 <- reshape(df.1[order(df.1$group), ], idvar=1, 
+     v.names=c('type', 'startdate', 'enddate'), timevar='group', 
+     direction='wide') 

> ## sort by id 
> df.2 <- df.2[order(df.2$id), ] 

> df.2 
#  id type.1 startdate.1 enddate.1 type.2 startdate.2 enddate.2 type.3 
# 1.2 1  W 2006-08-01 2007-08-29  A 2006-08-20 2006-12-06  P 
# 2.1 2  A 2006-01-05 2007-07-02  Q 2008-01-15 2008-02-07 <NA> 
#  startdate.3 enddate.3 
# 1.2 2007-08-18 2007-09-27 
# 2.1  <NA>  <NA> 
相关问题