基于 2 列拆分列
split column based on 2 columns
我有一个 table 格式如下:
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 等等。
因此 table 看起来像这样(示例中只有第一条记录):
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
所以我可能需要一些条件格式或其他东西。我希望有 Dpylr
和 plyr
的解决方案。
从其他问题开始尝试:
library(data.table)
tst <- setDT(tstDF)[, lapply(.SD, function(x) toString(na.omit(x))), by = t_id]
希望有人能解决这个问题。
我会合并成一个日期变量,然后为每封电子邮件创建一个计数器,然后使用重塑。这假设数据按电子邮件排序。
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')
问题中没有描述 t_id
和 date
的细节,所以在 (1) 中我们假设每个 [=18= 最多有 3 个 t_id
值] 并且它们出现的顺序分别对应于 date1
、date2
和 date3
,所有其他 date
值为 NA。例如,如果特定电子邮件有 2 个 t_id
值,那么第一个将 date1
作为日期,date2
和 date3
为 NA。第二个将 date2
作为日期,date1
和 date3
将是 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
,每个 email
有 k
行。 long
中每个 email
的第一行对应于第一个 tid
和 date
等等,直到第 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))
我有一个 table 格式如下:
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 等等。
因此 table 看起来像这样(示例中只有第一条记录):
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
所以我可能需要一些条件格式或其他东西。我希望有 Dpylr
和 plyr
的解决方案。
从其他问题开始尝试:
library(data.table)
tst <- setDT(tstDF)[, lapply(.SD, function(x) toString(na.omit(x))), by = t_id]
希望有人能解决这个问题。
我会合并成一个日期变量,然后为每封电子邮件创建一个计数器,然后使用重塑。这假设数据按电子邮件排序。
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')
问题中没有描述 t_id
和 date
的细节,所以在 (1) 中我们假设每个 [=18= 最多有 3 个 t_id
值] 并且它们出现的顺序分别对应于 date1
、date2
和 date3
,所有其他 date
值为 NA。例如,如果特定电子邮件有 2 个 t_id
值,那么第一个将 date1
作为日期,date2
和 date3
为 NA。第二个将 date2
作为日期,date1
和 date3
将是 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
,每个 email
有 k
行。 long
中每个 email
的第一行对应于第一个 tid
和 date
等等,直到第 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))