2016-11-16 43 views
0

我有如下因素格式的表格:分列基于2列

 t_id  date1  date2 date3 email 
100678318 2016-09-05  <NA> <NA> [email protected] 
100678319  <NA> 2016-10-05 <NA> [email protected] 
100732587 2016-11-01  <NA> <NA> [email protected] 
100689822 2016-09-18  <NA> <NA> [email protected] 
100640340 2016-08-01  <NA> <NA> [email protected] 
100641415  <NA> 2016-08-02 <NA> [email protected] 

现在我想将数据改变为不同的格式。 (宽) 要多一点电子邮件应分组到1行。如果我们有一个t_id,那么一旦我们想让它们结束,就像t_id_1 date1 t_id_2 date2等等。

使表看起来像这样(为例如仅第一条记录):

email    t_id_1  date1  t_id_2  date2  t_id_3 date3 
[email protected] 100678318 2016-09-05 100678319 2016-10-05 NA NA 

所以也许我需要一些条件格式什么的。我希望能与Dpylrplyr解决方案。

尝试从其他问题:

library(data.table) 
tst <- setDT(tstDF)[, lapply(.SD, function(x) toString(na.omit(x))), by = t_id] 

希望有一个人有这个问题的解决方案。

+0

你想要一个宽幅,不长格式。也许[这篇文章](http://stackoverflow.com/questions/5890584/how-to-reshape-data-from-long-to-wide-format)将会有所帮助。 – lmo

+0

谢谢改变了! –

回答

2

t_iddate的细节在问题没有描述所以在(1)中,我们假设有最多3个t_id值每email和它们出现在对应于date1date2和顺序date3分别与所有其他date值为NA。例如,如果特定电子邮件的值为2 t_id,那么第一个将具有date1作为日期,而date2date3为NA。第二个将有date2作为日期,date1date3将是NA。在(2)中,我们假设相同,除了我们概括为k而不是3。

没有使用包。

1)使用by分裂上email然后手动构造的行的每个。最后rbind行在一起。

do.call("rbind", 
    by(DF, DF$email, function(x) { 
    t_id <- c(x$t_id, NA, NA, NA)[1:3] 
    date <- c(na.omit(c(x$date1, x$date2, x$date3)), NA, NA, NA)[1:3] 
    data.frame(email = x$email[1], 
       t_id1 = t_id[1], date1 = date[1], 
       t_id2 = t_id[2], date2 = date[2], 
       t_id3 = t_id[3], date3 = date[3] 
    ) 
    } 
)) 

,并提供:

       email  t_id1  date1  t_id2  date2 
[email protected]     [email protected] 100689822 2016-09-18  NA  <NA> 
[email protected] [email protected] 100732587 2016-11-01  NA  <NA> 
[email protected]  [email protected] 100640340 2016-08-01 100641415 2016-08-02 
[email protected]  [email protected] 100678318 2016-09-05 100678319 2016-10-05 
        t_id3 date3 
[email protected]   NA <NA> 
[email protected] NA <NA> 
[email protected]  NA <NA> 
[email protected]  NA <NA> 

2)如果需要,我们可以概括这个高达k日期和t_id值。在这种情况下,rbind/by产生新的数据帧long,其具有k行,每个email。每个email的第一行long对应于第一个tiddate等等直到第k个。 long随后被重新整形。

is.date <- grepl("date", names(DF)) 
k <- sum(is.date) 

long <- do.call("rbind", 
    by(DF, DF$email, function(x) 
    data.frame(email = x$email[1], 
     time = 1:k, 
     t_id = c(x$t_id, rep(NA, k))[1:k], 
     date = c(na.omit(do.call("c", x[is.date])), rep(NA, k))[1:k] 
    ) 
) 
) 
reshape(long, dir = "wide", idvar = "email") 

,并提供:

        email t_id.1  date.1 t_id.2  date.2 t_id.3 date.3 
[email protected]     [email protected] 100689822 2016-09-18  NA  <NA>  NA <NA> 
[email protected] [email protected] 100732587 2016-11-01  NA  <NA>  NA <NA> 
[email protected] [email protected] 100640340 2016-08-01 100641415 2016-08-02  NA <NA> 
[email protected] [email protected] 100678318 2016-09-05 100678319 2016-10-05  NA <NA> 

注:输入DF在重现的形式被假定为:

Lines <- "t_id  date1  date2 date3 email 
100678318 2016-09-05  <NA> <NA> [email protected] 
100678319  <NA> 2016-10-05 <NA> [email protected] 
100732587 2016-11-01  <NA> <NA> [email protected] 
100689822 2016-09-18  <NA> <NA> [email protected] 
100640340 2016-08-01  <NA> <NA> [email protected] 
100641415  <NA> 2016-08-02 <NA> [email protected]" 

DF <- transform(read.table(text = Lines, header = TRUE, na.strings = "<NA>"), 
      date1 = as.Date(date1), 
      date2 = as.Date(date2), 
      date3 = as.Date(date3)) 
+0

感谢您的广泛阐述。我会开始尝试!如果你想帮助我,也许我会回来一些额外的细节。 –

2

我会合并成一个日期变量,然后为每个电子邮件创建一个计数器,然后使用重塑。这假定数据是通过电子邮件排序的。

library(reshape2) 

coalesce <- function(...) { 
    apply(cbind(...), 1, function(x) x[which(!is.na(x))[1]]) 
} 

df$date <- as.Date(coalesce(df$date1, df$date2, df$date3), origin = '1970-01-01') 
df$id <- 1 
for (i in 2:nrow(df)) { 
    if (df$email[i] == df$email[i - 1]) { 
    df$id[i] <- df$id[i] + 1 
    } 
} 

reshape(df[ c('id', 'date', 't_id', 'email')], idvar = 'email', timevar = 'id', direction = 'wide') 
+0

确实很好的解决方案,但这只给了我第2个t_id和日期。在我的完整DF中,我平均有大约8笔交易。你可能会更多地为for循环做些调整,以便我可以将代码更改为我的需求? –