我试图获得最快的(并在某种程度上优雅)的方法来提取单个元素的数据。几个标准下的表(支持表)。
为了简单起见,一个明显缩短的例子:
library(data.table)
dt <- data.table(
person = c("Rick", "Michelle", "Richard", "Ryan", "Larry"),
criteria = c("A", "B", "C", "A", "C"),
number = c(5, 62, 25, 77, 91),
gender = c("M", "F", "M", "M", "M")
)
supp.dt <- data.table(
crits = c("A", "B", "C"),
ID = c("ID.1", "ID.2", "ID.3")
)
value.dt <- data.table(
ID.1M = runif(100, 0, 1),
ID.1F = runif(100, 0, 1),
ID.2M = runif(100, 1, 2),
ID.2F = runif(100, 1, 2),
ID.3M = runif(100, 2, 3),
ID.3F = runif(100, 2, 3)
)
getValue <- function(crit=NULL, numb=NULL, gend=NULL) {
return(value.dt[numb, paste0(supp.dt[crits == crit]$ID, gend), with = F])
}
dt$value <- mapply(getValue, dt$criteria, dt$number, dt$gender)
基准和结果:
library(microbenchmark)
runmapply <- function() {
dt$value <- mapply(getValue, dt$criteria, dt$number, dt$gender)
}
microbenchmark(
runmapply()
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# runmapply() 5.5528 5.979 7.912311 6.4392 8.4442 24.1152 100
这里的方法似乎是正确的,但是
- 我的数据有多达百万行
- 我需要提取多个值,实际上我使用13不同的值;我将它们存储为数据列表。表和
总之,对于数据量和不同的值来说,它花费的时间太长了。
提前感谢您对优化的任何建议。
更新:
我想塑造和连接桌子。但不知道该怎么接近。我想我不知道是什么数据。表所能做的。由于@langtang
更具体地说一下我提到的那13张表:他们有所有的数据。有100行但列数不同的表。我还应该提到列的名称各不相同,因此示例中的列名ID.1到ID.3设置错误。但这可以很容易地通过ID=str_sub(ID, 1, length(ID))来解决。
对于更多的值表,我们可以清楚地看到,标准为我们提供了到support .dt的连接,另一方面,它保存了13个data.表的所有信息。
所以我们可以看一下有两个值的例子。我还稍微改变了一下这些列名:
library(data.table)
dt <- data.table(
person = c("Rick", "Michelle", "Richard", "Ryan", "Larry"),
criteria = c("A", "B", "C", "A", "C"),
number = c(5, 62, 25, 77, 91),
gender = c("M", "F", "M", "M", "M")
)
supp.dt <- data.table(
crits = c("A", "B", "C"),
valueoneID = c("uno", "dos", "tres"),
valuetwoID = c("eins", "zwei", "drei")
) # for every valuetable there is a respective id column
valueone.dt <- data.table(
unoM = runif(100, 0, 1),
unoF = runif(100, 0, 1),
dosM = runif(100, 1, 2),
dosF = runif(100, 1, 2),
tresM = runif(100, 2, 3),
tresF = runif(100, 2, 3)
)
valuetwo.dt <- data.table(
einsM = runif(100, 0, 1),
einsF = runif(100, 0, 1),
zweiM = runif(100, 1, 2),
zweiF = runif(100, 1, 2),
dreiM = runif(100, 2, 3),
dreiF = runif(100, 2, 3)
)
我期望的输出应该是这样的:(ID列是不必要的)
gender person number valueone valuetwo
<char> <char> <int> <num> <num>
1: M Rick 5 0.8572478 0.2312414
2: M Ryan 77 0.6211473 0.8585884
3: F Michelle 62 1.8570321 1.2232323
4: M Richard 25 2.5732931 2.2323179
5: M Larry 91 2.0300149 2.0919987
我认为这种方法将取决于您的多个值的确切结构(13,以及它们存储的位置),但您可以考虑使用连接等。
melt(value.dt[, number:=.I],id.vars = "number", variable.name = "ID")[
,`:=`(ID=str_sub(ID, 1,4), gender=str_sub(ID,-1,-1))][
dt[supp.dt,on=c("criteria"="crits")],
on=.(ID,gender,number)]
输出:
number ID value gender person criteria
<int> <char> <num> <char> <char> <char>
1: 5 ID.1 0.8572478 M Rick A
2: 77 ID.1 0.6211473 M Ryan A
3: 62 ID.2 1.8570321 F Michelle B
4: 25 ID.3 2.5732931 M Richard C
5: 91 ID.3 2.0300149 M Larry C
更新如果您有多个"value"帧,你可以采取以下方法:
首先,将它们放入命名列表
value_frames = list("valueoneID" = valueone.dt,"valuetwoID" = valuetwo.dt)
其次,创建单个value.dt
数据。从value_frames
value.dt = rbindlist(
lapply(value_frames, (f) melt(f[,number:=.I], id.vars="number", variable.name="ID")),
idcol = "vsrc"
)
然后,将value.dt
连接到dt
和supp.dt
之间的连接的熔化版本,并将结果投射回wide。
dcast(
value.dt[,`:=`(ID = str_sub(ID,1,-2), gender=str_sub(ID,-1,-1))][
melt(dt[supp.dt,on=c("criteria"="crits")],
measure.vars = patterns("value"),
variable.name = "vsrc",
value.name = "ID"),
on=.(ID,gender,number,vsrc)],
gender+person+number~vsrc, value.var="value"
)