Mat*_*ina 5 string r stringr tidyr
我有一个data.frame由字母数字字符序列组成的id(例如id = c(A001, A002, B013)).我正在寻找一个简单的函数stringr或者stirngi很容易用这个字符串做数学运算(id + 1应该返回c(A002, A003, B014)).
我做了一个自定义函数来完成这个技巧,但是我觉得必须有一个更好/更有效/内部包的方式来实现这一点.
str_add_n <- function(df, string, n, width=3){
string <- enquo(string)
## split the string using pattern
df <- df %>%
separate(!!string,
into = c("text", "num"),
sep = "(?<=[A-Za-z])(?=[0-9])",
remove=FALSE
) %>%
mutate(num = as.numeric(num),
num = num + n,
num = stringr::str_pad(as.character(num),
width = width,
side = "left",
pad = 0
)
) %>%
unite(next_string, text:num, sep = "")
return(df)
}
Run Code Online (Sandbox Code Playgroud)
让我们做一个玩具 df
df <- data.frame(id = c("A001", "A002", "B013"))
str_add_n(df, id, 1)
id next_string
1 A001 A002
2 A002 A003
3 B013 B014
Run Code Online (Sandbox Code Playgroud)
再次,这是有效的,我想知道是否有更好的方法来做到这一点,所有调整欢迎!
基于建议的答案,我运行了一些基准测试,看起来两者都非常接近,我会倾向于str_add_n_2(我更改了名称以便能够运行两者,并采取了建议x<-as.character(x))
microbenchmark::microbenchmark(question = str_add_n(df, id, 1),
answer = df %>% mutate_at(vars(id), funs(str_add_n_2(., 1))),
string_add = df %>% mutate_at(vars(id), funs(string_add(as.character(.)))))
Run Code Online (Sandbox Code Playgroud)
哪个收益率
Unit: milliseconds
expr min lq mean median uq
question 4.312094 4.448391 4.695276 4.570860 4.755748
answer 2.932146 3.017874 3.191262 3.117627 3.240688
string_add 3.388442 3.466466 3.699363 3.534416 3.682762
max neval cld
10.29253 100 c
8.24967 100 a
9.05441 100 b
Run Code Online (Sandbox Code Playgroud)
欢迎进行更多调整!
这是一种方法gsubfn
id <- c("A001", "A002", "B013")
library(gsubfn)
gsubfn("([0-9]+)", function(x) sprintf("%03.0f", as.numeric(x) + 1), id)
#[1] "A002" "A003" "B014"
Run Code Online (Sandbox Code Playgroud)
你可以把它变成一个函数
string_add <- function(string, add = 1, width = 3) {
gsubfn::gsubfn("([0-9]+)", function(x) sprintf(paste0("%0", width, ".0f"), as.numeric(x) + add), string)
}
string_add(id, add = 10, width = 5)
#"A00011" "A00012" "B00023"
Run Code Online (Sandbox Code Playgroud)
我建议基于字符串向量定义函数更容易,而不是对其进行硬编码以在框架中查找列;对于后者,您始终可以使用类似的东西mutate_at(vars(id,...), funs(str_add_n))。
str_add_n <- function(x, n = 1L) {
gr <- gregexpr("\\d+", x)
reg <- regmatches(x, gr)
widths <- nchar(reg)
regmatches(x, gr) <- sprintf(paste0("%0", widths, "d"), as.integer(reg) + n)
x
}
vec <- c("A001", "A002", "B013")
str_add_n(vec)
# [1] "A002" "A003" "B014"
Run Code Online (Sandbox Code Playgroud)
如果在一个框架中:
df <- data.frame(id = c("A001", "A002", "B013"), x = 1:3,
stringsAsFactors = FALSE)
library(dplyr)
df %>%
mutate_at(vars(id), funs(str_add_n(., 3)))
# id x
# 1 A004 1
# 2 A005 2
# 3 B016 3
Run Code Online (Sandbox Code Playgroud)
警告:这默默地需要 true character,而不是factor......可能的防御策略可能是添加x <- as.character(x)到函数定义中。
更新:mutate_at已被取代,首选用途across是:
str_add_n <- function(x, n = 1L) {
gr <- gregexpr("\\d+", x)
reg <- regmatches(x, gr)
widths <- nchar(reg)
regmatches(x, gr) <- sprintf(paste0("%0", widths, "d"), as.integer(reg) + n)
x
}
vec <- c("A001", "A002", "B013")
str_add_n(vec)
# [1] "A002" "A003" "B014"
Run Code Online (Sandbox Code Playgroud)
或者更直接
df <- data.frame(id = c("A001", "A002", "B013"), x = 1:3,
stringsAsFactors = FALSE)
library(dplyr)
df %>%
mutate_at(vars(id), funs(str_add_n(., 3)))
# id x
# 1 A004 1
# 2 A005 2
# 3 B016 3
Run Code Online (Sandbox Code Playgroud)