我有一个数据框,我想添加一个包含不重复的字母数字值的列。
首先,我改编了一个我在博客上找到的功能。 (https://ryouready.wordpress.com/2008/12/18/generate-random-string-name/)
idGenerator <- function(n, lengthId) {
alphaNum <- c(0:9, letters, LETTERS)
if (n > length(alphaNum)^lengthId) {
return("Error! n > perms : Infinite loop")
}
idList <- rep(NULL, n)
for (i in 1:n) {
idList[i] <- paste(sample(alphaNum,
lengthId, replace = TRUE), collapse = "")
while(idList[i] %in% idList[-i]) {
idList[i] <- paste(sample(alphaNum,
lengthId, replace = TRUE), collapse = "")
}
}
return(idList)
}
我的问题是我的数据帧有大约250k行,所以n = 250k这个函数只是永远运行。
我知道n = 250k时,如果我增加id字符串的长度(lengthId
),获得相同字符串的几率是不现实的,所以while
循环是浪费资源,但我真的需要确保不会发生,我的意思是“确定”控制结构。
所以我找到了一种更有效的方法,而不是调用while
并检查循环中每个i
的所有向量,我检查最终向量中是否有重复:
idGenerator <- function(n, lengthId) {
alphaNum <- c(0:9, letters, LETTERS)
if (n > length(alphaNum)^lengthId) {
return("Error! n > perms : Infinite loop")
}
idList <- 1:n
for (i in 1:n) {
idList[i] <- paste(sample(alphaNum,
lengthId, replace = TRUE), collapse = "")
}
while(any(duplicated(idList))) {
idList[which(duplicated(idList))] <- paste(sample(alphaNum, lengthId,
replace = TRUE), collapse = "")
}
return(idList)
}
如果while
必须运行很多次,那么速度很慢=&gt;当n非常接近排列数时。
> system.time(idGenerator(62^2, 2))
utilisateur système écoulé
8.00 0.00 8.02
> system.time(idGenerator(62^3, 3))
Timing stopped at: 584.35 16.66 602.46
但是对于长id字符串来说这是完全可以接受的:
> system.time(idGenerator(250000, 12))
utilisateur système écoulé
3.2 0.0 3.2
然而,创建一个列仍然是3秒+所以我正在寻找更快的方法。 我知道循环不是那么好,我应该更喜欢矢量化,但我不是真正的代码优化大师。所以,如果您有任何想法,请提前感谢您。
答案 0 :(得分:10)
我建议查看“stringi”包中的stri_rand_strings
函数:
library(stringi)
stri_rand_strings(10, 3)
# [1] "wsm" "FvH" "UXm" "14t" "rvv" "Pfo" "mzK" "20b" "O9P" "ZOr"
system.time(X <- stri_rand_strings(250000, 12))
# user system elapsed
# 0.327 0.003 0.333
length(unique(X))
# [1] 250000
head(X)
# [1] "WxRPZjt0uFaI" "E129Ug0Vif3f" "qXGzQDO0LzvG"
# [4] "9D4guGMf2jZ1" "Qw1p7reH4XKg" "0gziFNnZ16p8"