我正在嘗試獲得最快(并且在某種程度上優雅)的方法來根據一些標準(使用支持表)從 data.table 中提取單個元素。
為簡單起見,一個顯著縮短的示例:
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 個不同的值;我首先將它們存盤為 data.tables 串列,然后
總之,資料量和不同的值花費的時間太長。
在此先感謝您提供任何優化想法。
更新:
我考慮過塑造和加入表格。但不知道如何接近。我想我不知道 data.table 能做什么。謝謝@langtang
更具體地說,我提到的那 13 個表:它們的所有 data.tables 都有 100 行,但列數不同。我還應該提到列的名稱各不相同,因此示例中的列名 ID.1 到 ID.3 設定錯誤。但這可以通過 ID=str_sub(ID, 1, length(ID)) 輕松解決。
有了更多的值表,我們可以清楚地看到,標準為我們提供了與 supp.dt 的連接,另一方面,supp.dt 將所有資訊保存到 13 個 data.tables。
因此,我們可以查看帶有兩個 value.dt 的示例,并且我還稍微更改了這些列名:
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
uj5u.com熱心網友回復:
我認為該方法將取決于您的多個值的確切結構(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_frames = list("valueoneID" = valueone.dt,"valuetwoID" = valuetwo.dt)
其次,創建一個單獨的value.dtdata.table,將這些不同幀的融合版本從value_frames
value.dt = rbindlist(
lapply(value_frames, \(f) melt(f[,number:=.I], id.vars="number", variable.name="ID")),
idcol = "vsrc"
)
然后,連接到andvalue.dt之間的連接的融合版本,并將結果轉換回 Wide。dtsupp.dt
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"
)
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/468450.html
上一篇:我如何推斷性能影響(更改為更緊湊的48位整數表示)?
下一篇:以索引形式回傳結果的二分搜索
