基于2列拆分列

时间:2016-11-16 14:01:50

标签: r dplyr plyr

我有一个以下格式的表格:

      t_id      date1      date2 date3 email
 100678318 2016-09-05       <NA>  <NA>  natas@gmail.com
 100678319       <NA> 2016-10-05  <NA>  natas@gmail.com
 100732587 2016-11-01       <NA>  <NA>  1000988@boerman.nl
 100689822 2016-09-18       <NA>  <NA>  10@line.nl
 100640340 2016-08-01       <NA>  <NA>  1111tk68@net.nl
 100641415       <NA> 2016-08-02  <NA>  1111tk68@net.nl

现在我想将数据更改为其他格式。 (宽) 为了更复杂,应将电子邮件分组为1行。如果我们有一个更多的t_id,那么我们希望它们最终会像t_id_1 date1 t_id_2 date2那样结束。

因此表格看起来像这样(只有示例的第一条记录):

email             t_id_1      date1        t_id_2      date2      t_id_3 date3
natas@gmail.com   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]

希望有人能解决这个问题。

2 个答案:

答案 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')

答案 1 :(得分:2)

t_iddate的详细信息未在问题中描述,因此在(1)中我们假设每t_id最多有3 email个值,它们显示在与date1date2date3分别对应的顺序中,所有其他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
10@line.nl                 10@line.nl 100689822 2016-09-18        NA       <NA>
1000988@boerman.nl 1000988@boerman.nl 100732587 2016-11-01        NA       <NA>
1111tk68@net.nl       1111tk68@net.nl 100640340 2016-08-01 100641415 2016-08-02
natas@gmail.com       natas@gmail.com 100678318 2016-09-05 100678319 2016-10-05
                   t_id3 date3
10@line.nl            NA  <NA>
1000988@boerman.nl    NA  <NA>
1111tk68@net.nl       NA  <NA>
natas@gmail.com       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
10@line.nl.1                   10@line.nl 100689822 2016-09-18        NA       <NA>     NA   <NA>
1000988@boerman.nl.1   1000988@boerman.nl 100732587 2016-11-01        NA       <NA>     NA   <NA>
1111tk68@net.nl.date11    1111tk68@net.nl 100640340 2016-08-01 100641415 2016-08-02     NA   <NA>
natas@gmail.com.date11    natas@gmail.com 100678318 2016-09-05 100678319 2016-10-05     NA   <NA>

注意:可重复形式的输入DF被假定为:

Lines <- "t_id      date1      date2 date3 email
 100678318 2016-09-05       <NA>  <NA>  natas@gmail.com
 100678319       <NA> 2016-10-05  <NA>  natas@gmail.com
 100732587 2016-11-01       <NA>  <NA>  1000988@boerman.nl
 100689822 2016-09-18       <NA>  <NA>  10@line.nl
 100640340 2016-08-01       <NA>  <NA>  1111tk68@net.nl
 100641415       <NA> 2016-08-02  <NA>  1111tk68@net.nl"

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