将数据 table 中的行熔化或复制一定次数并在 R 中包含计数器
Melt or Replicate rows in a data table a certain number of times and include counter in R
我想 "expand" 一个数据框,将某些列上的信息复制到第五列指示的次数。
用 R 完成这个任务的效率最高的是什么? (对数据开放 Table 或 Dplyer,重塑解决方案)。
原文Dataframe/DataTable:
f_1 f_2 d_1 d_2 i_1
1: 1 A 2016-01-01 <NA> NA
2: 2 A 2016-01-02 <NA> NA
3: 2 B 2016-01-03 2016-01-01 2
4: 3 C 2016-01-04 <NA> NA
5: 4 D 2016-01-05 2016-01-02 5
想要Dataframe/DataTable
f_1 f_2 d_1 d_2 i_1
1: 1 A 2016-01-01 <NA> NA
2: 2 A 2016-01-02 <NA> NA
3: 2 B 2016-01-03 2016-01-01 1
4: 2 B 2016-01-03 2016-01-01 2
5: 3 C 2016-01-04 <NA> NA
6: 4 D 2016-01-05 2016-01-02 1
7: 4 D 2016-01-05 2016-01-02 2
8: 4 D 2016-01-05 2016-01-02 3
9: 4 D 2016-01-05 2016-01-02 4
10: 4 D 2016-01-05 2016-01-02 5
可重现的数据:
DT <- data.table(
f_1 = factor(c(1,2,2,3,4)),
f_2 = factor(c("A", "A", "B", "C", "D")),
d_1 = as.Date(c("2016-01-01","2016-01-02","2016-01-03","2016-01-04","2016-01-05")),
d_2 = as.Date(c(NA,NA,"2016-01-01",NA,"2016-01-02")),
i_1 = as.integer(c(NA,NA,2,NA,5)))
谢谢,如有重复请见谅。我正在为这种重塑练习而苦恼。
这是一个data.table
解决方案。基本上,按要复制的那些列分组,并使用 i_1
中的数字生成整数序列
DT[, .(i_1=if(!is.na(i_1)) seq_len(i_1) else i_1),
by=c(names(DT)[-ncol(DT)])]
输出:
f_1 f_2 d_1 d_2 i_1
1: 1 A 2016-01-01 <NA> NA
2: 2 A 2016-01-02 <NA> NA
3: 2 B 2016-01-03 2016-01-01 1
4: 2 B 2016-01-03 2016-01-01 2
5: 3 C 2016-01-04 <NA> NA
6: 4 D 2016-01-05 2016-01-02 1
7: 4 D 2016-01-05 2016-01-02 2
8: 4 D 2016-01-05 2016-01-02 3
9: 4 D 2016-01-05 2016-01-02 4
10: 4 D 2016-01-05 2016-01-02 5
或使用 data.table
的另一种方式。对于每一行,使用 i_1
创建一个数字序列,并使用 c(.SD[, -"i_1], .....
将原始数据添加到该序列,最后删除 by
列
DT[, c(.SD[, -"i_1"], .(i_1=if (!is.na(i_1)) seq_len(i_1) else i_1)),
by=seq_len(DT[,.N])][,-1L]
当 NA
时,您可以将 i_1
替换为 1
吗?如果是这样,下面的内容会稍微更具可读性:
首先,将行重复指定的次数(临时 考虑 i_1
的缺失值,使用 replace
@Frank 提供):
DT_out = DT[rep(1:.N, replace(i_1, is.na(i_1), 1L))]
如果我们已经替换了 DT[is.na(i_1), i_1 := 1L]
,这可能只是 DT[rep(1:.N, i_1)]
。
剩下的就是更新 i_1
的值。根据您的数据的详细信息,有更简单的版本。这里我认为是更通用的版本:
DT_out[!is.na(i_1), i_1 := rowidv(.SD), .SDcols = !'i_1'][]
# f_1 f_2 d_1 d_2 i_1
# 1: 1 A 2016-01-01 <NA> NA
# 2: 2 A 2016-01-02 <NA> NA
# 3: 2 B 2016-01-03 2016-01-01 1
# 4: 2 B 2016-01-03 2016-01-01 2
# 5: 3 C 2016-01-04 <NA> NA
# 6: 4 D 2016-01-05 2016-01-02 1
# 7: 4 D 2016-01-05 2016-01-02 2
# 8: 4 D 2016-01-05 2016-01-02 3
# 9: 4 D 2016-01-05 2016-01-02 4
# 10: 4 D 2016-01-05 2016-01-02 5
rowid
和 rowidv
给出由传递的变量定义的组内的行号。您可以与 rowid(f_2)
、rowid(f_1)
和 rowid(f_1, f_2)
进行比较,以了解我的意思。 rowidv(.SD)
是 rowid(f_1, f_2, d_1, d_2)
的 shorthand,因为我们从 .SD
.
的列中排除了 i_1
我想 "expand" 一个数据框,将某些列上的信息复制到第五列指示的次数。
用 R 完成这个任务的效率最高的是什么? (对数据开放 Table 或 Dplyer,重塑解决方案)。
原文Dataframe/DataTable:
f_1 f_2 d_1 d_2 i_1
1: 1 A 2016-01-01 <NA> NA
2: 2 A 2016-01-02 <NA> NA
3: 2 B 2016-01-03 2016-01-01 2
4: 3 C 2016-01-04 <NA> NA
5: 4 D 2016-01-05 2016-01-02 5
想要Dataframe/DataTable
f_1 f_2 d_1 d_2 i_1
1: 1 A 2016-01-01 <NA> NA
2: 2 A 2016-01-02 <NA> NA
3: 2 B 2016-01-03 2016-01-01 1
4: 2 B 2016-01-03 2016-01-01 2
5: 3 C 2016-01-04 <NA> NA
6: 4 D 2016-01-05 2016-01-02 1
7: 4 D 2016-01-05 2016-01-02 2
8: 4 D 2016-01-05 2016-01-02 3
9: 4 D 2016-01-05 2016-01-02 4
10: 4 D 2016-01-05 2016-01-02 5
可重现的数据:
DT <- data.table(
f_1 = factor(c(1,2,2,3,4)),
f_2 = factor(c("A", "A", "B", "C", "D")),
d_1 = as.Date(c("2016-01-01","2016-01-02","2016-01-03","2016-01-04","2016-01-05")),
d_2 = as.Date(c(NA,NA,"2016-01-01",NA,"2016-01-02")),
i_1 = as.integer(c(NA,NA,2,NA,5)))
谢谢,如有重复请见谅。我正在为这种重塑练习而苦恼。
这是一个data.table
解决方案。基本上,按要复制的那些列分组,并使用 i_1
DT[, .(i_1=if(!is.na(i_1)) seq_len(i_1) else i_1),
by=c(names(DT)[-ncol(DT)])]
输出:
f_1 f_2 d_1 d_2 i_1
1: 1 A 2016-01-01 <NA> NA
2: 2 A 2016-01-02 <NA> NA
3: 2 B 2016-01-03 2016-01-01 1
4: 2 B 2016-01-03 2016-01-01 2
5: 3 C 2016-01-04 <NA> NA
6: 4 D 2016-01-05 2016-01-02 1
7: 4 D 2016-01-05 2016-01-02 2
8: 4 D 2016-01-05 2016-01-02 3
9: 4 D 2016-01-05 2016-01-02 4
10: 4 D 2016-01-05 2016-01-02 5
或使用 data.table
的另一种方式。对于每一行,使用 i_1
创建一个数字序列,并使用 c(.SD[, -"i_1], .....
将原始数据添加到该序列,最后删除 by
列
DT[, c(.SD[, -"i_1"], .(i_1=if (!is.na(i_1)) seq_len(i_1) else i_1)),
by=seq_len(DT[,.N])][,-1L]
当 NA
时,您可以将 i_1
替换为 1
吗?如果是这样,下面的内容会稍微更具可读性:
首先,将行重复指定的次数(临时 考虑 i_1
的缺失值,使用 replace
@Frank 提供):
DT_out = DT[rep(1:.N, replace(i_1, is.na(i_1), 1L))]
如果我们已经替换了 DT[is.na(i_1), i_1 := 1L]
,这可能只是 DT[rep(1:.N, i_1)]
。
剩下的就是更新 i_1
的值。根据您的数据的详细信息,有更简单的版本。这里我认为是更通用的版本:
DT_out[!is.na(i_1), i_1 := rowidv(.SD), .SDcols = !'i_1'][]
# f_1 f_2 d_1 d_2 i_1
# 1: 1 A 2016-01-01 <NA> NA
# 2: 2 A 2016-01-02 <NA> NA
# 3: 2 B 2016-01-03 2016-01-01 1
# 4: 2 B 2016-01-03 2016-01-01 2
# 5: 3 C 2016-01-04 <NA> NA
# 6: 4 D 2016-01-05 2016-01-02 1
# 7: 4 D 2016-01-05 2016-01-02 2
# 8: 4 D 2016-01-05 2016-01-02 3
# 9: 4 D 2016-01-05 2016-01-02 4
# 10: 4 D 2016-01-05 2016-01-02 5
rowid
和 rowidv
给出由传递的变量定义的组内的行号。您可以与 rowid(f_2)
、rowid(f_1)
和 rowid(f_1, f_2)
进行比较,以了解我的意思。 rowidv(.SD)
是 rowid(f_1, f_2, d_1, d_2)
的 shorthand,因为我们从 .SD
.
i_1