这可能很简单,但我很难找到一种方法来做到这一点。我有一个dt包含许多列的 data.table。如果其中一列sex包含值Male、Female和"",我想将这些值重新映射到Male= M、Female=F和""=NA。我怎样才能做到这一点而不使用ifelse.
有许多解决方案可用。在这里,我将重点关注base-R 或data.table解决方案。
library(data.table)
dt <- data.table(sex = c("Male", "Female", ""))
Run Code Online (Sandbox Code Playgroud)
您可以使用fcase(基本上是嵌套的ifelse):
dt[, sex := fcase(sex == "Male", "M", sex == "Female", "F")]
sex
1: M
2: F
3: <NA>
Run Code Online (Sandbox Code Playgroud)
请注意,默认情况下,所有不匹配的内容都fcase设置为NA。如果需要,您可以随时提供更多“案例”(如sex == "", NA, ...)。
您可以将其设置为一个因素并重新标记级别:
dt[, sex := factor(sex, levels = c("Male", "Female"), labels = c("M", "F"))]
sex
1: M
2: F
3: <NA>
Run Code Online (Sandbox Code Playgroud)
dt[.(old = c("Male", "Female", ""), new = c("M", "F", NA)), on = .(sex = old), sex := new]
sex
1: M
2: F
3: <NA>
Run Code Online (Sandbox Code Playgroud)
使用substring。
dt[, sex := substring(replace(sex, sex == "", NA), 1, 1)]
sex
1: M
2: F
3: <NA>
Run Code Online (Sandbox Code Playgroud)
一个data.table版本match(受到@jblood94的启发)。
dt[, sex := c("M", "F", NA)[chmatch(sex, c("Male", "Female", ""))]]
sex
1: M
2: F
3: <NA>
Run Code Online (Sandbox Code Playgroud)
创建查找表。
LUT <- data.table(sex = c("Male", "Female", ""), to=c("M", "F", NA), key = "sex")
dt[, sex := LUT[.SD, to]]
sex
1: M
2: F
3: <NA>
Run Code Online (Sandbox Code Playgroud)
如果您有其他解决方案,我可以在此处添加,请告诉我!
我使用sample数据是因为有序值使选项 1和选项 2比其他选项更有优势。*
library(microbenchmark)
#data
dt.bm <- data.table(sex = sample(rep(c("Male", "Female", ""), 100000)))
#benchmarking
microbenchmark(
option_1 = copy(dt.bm)[, sex := fcase(sex == "Male", "M", sex == "Female", "F")],
option_2 = copy(dt.bm)[, sex := factor(sex, levels = c("Male", "Female"), labels = c("M", "F"))],
option_3 = copy(dt.bm)[.(old=c("Male","Female",""), new=c("M","F",NA)), on=.(sex=old), sex := new],
option_4 = copy(dt.bm)[, sex := substring(replace(sex, sex == "", NA), 1, 1)],
option_5 = copy(dt.bm)[, sex := c("M", "F", NA)[chmatch(sex, c("Male", "Female", ""))]],
option_6 = {LUT <- data.table(sex = c("Male", "Female", ""), to=c("M", "F", NA), key = "sex"); copy(dt.bm)[, sex := LUT[.SD, to]]},
times = 10L
)
Run Code Online (Sandbox Code Playgroud)
就速度而言,选项 5是性能最好的选项。**
#results
Unit: milliseconds
expr min lq mean median uq max neval
option_1 6.7219 6.7816 7.76613 6.85335 9.7207 10.3584 10
option_2 6.1356 6.1981 7.18201 6.29060 9.2294 9.4921 10
option_3 8.6486 8.6935 10.61704 10.29420 12.5258 13.0865 10
option_4 8.1740 8.2124 9.10800 8.31170 9.1615 12.3198 10
option_5 3.3497 3.3843 3.84333 3.44340 3.4822 7.5465 10
option_6 6.0769 6.2583 6.99274 6.51460 6.6087 9.6276 10
Run Code Online (Sandbox Code Playgroud)
*在有序情况下,选项 2 的平均计时时间约为 3.9 毫秒(数据未显示)。
**这只是考虑base和data.table解决方案。按照 @s_baldurs 答案的建议使用collapse::join,平均时间约为 3.1 毫秒,而fastmatch::fmatch(@jblood94) 是迄今为止最快的方法,为 3.0 毫秒(数据未显示)。