我有一个简单的数据框:
df <- data.frame(test = c("test_A_1_1.txt", "test_A_2_1.txt", "test_A_3_1.txt"), value = c(0.51, 0.52, 0.56)) test value 1 test_A_1_1.txt 0.51 2 test_A_2_1.txt 0.52 3 test_A_3_1.txt 0.56
预期产量
我想将数字复制到第1列的字符串末尾,并将其分别放在第3列或第4列中,如下所示:
test value new new 1 test_A_1.txt 0.51 1 1 2 test_A_2.txt 0.52 2 1 3 test_A_3.txt 0.56 3 1
尝试
使用以下代码,我可以从字符串中提取数字:
library(stringr) as.numeric(str_extract_all("test_A_3.txt", "[0-9]+")[[1]])[1] # Extracts the first number as.numeric(str_extract_all("test_A_3.txt", "[0-9]+")[[1]])[2] # Extracts the second number
我想将此代码应用于第一列的所有值:
library(tidyverse) df %>% mutate(new = as.numeric(str_extract_all(df$test, "[0-9]+")[[1]])[1])
但是,这导致new
只有数字的列1
。我究竟做错了什么?
为什么不使用基础R解决方案?
df$new <- as.numeric(gsub("[^[:digit:]]+", "", df$test)) df # test value new #1 test_A_1.txt 0.51 1 #2 test_A_2.txt 0.52 2 #3 test_A_3.txt 0.56 3
编辑。
按照用户@camille的答案中的示例,其中字符串可能具有不同数量的数字,这是使用package的解决方案stringr
。
df1 <- data.frame(test = c("test_A_1.txt", "test_A_2.txt", "test_A_3.txt"), value = c(0.51, 0.52, 0.56)) df2 <- data.frame(test = c("test_A_1_1.txt", "test_A_2_1.txt", "test_A_3_1.txt"), value = c(0.51, 0.52, 0.56)) df3 <- data.frame(test = c("test_A_1_1.txt", "test_A_2_1.txt", "test_A_3_1.txt", "test_A_4_2_1.txt"), value = c(0.51, 0.52, 0.56, 2)) num2cols <- function(DF, col = "test"){ s <- stringr::str_extract_all(DF[[col]], "[[:digit:]]+") Max <- max(sapply(s, length)) new <- do.call(rbind, lapply(s, function(x){ as.numeric(c(x, rep(NA, Max - length(x)))) })) names_new <- paste0("new", seq.int(ncol(new))) setNames(cbind(DF, new), c(names(DF), names_new)) } num2cols(df1) num2cols(df2) num2cols(df3)
我们可以使用parse_number
从readr
library(dplyr) library(purrr) library(stringr) df %>% mutate(new = readr::parse_number(as.character(test)))
关于OP的问题,它仅从中选择第一个list
元素([[1]]
)str_extract_all
(返回list
)。相反,最好使用,str_extract
因为我们只需要提取一个或多个数字(\\d+
)的第一个实例
df %>% mutate(new = as.numeric(str_extract(test, "[0-9]+")))
如果我们需要从得到的输出str_extract_all
(万一),unlist
将list
到vector
,然后应用as.numeric
上vector
df %>% mutate(new = as.numeric(unlist(str_extract_all(test, "[0-9]+"))))
如果有多个实例,则它保持为list
转换成之后numeric
通过经循环list
与元件map
df %>% mutate(new = map(str_extract_all(test, "[0-9]+"), as.numeric))
注意:str_extract
基于解决方案首先发布在这里。
在中base R
,我们可以使用regexpr
df$new <- as.numeric(regmatches(df$test, regexpr("\\d+", df$test)))
随着更新的例子,如果我们需要得到的数字的两个实例,第一个可以与提取str_extract
,最后(stri_extract_last
-从stringi
可作为良好),通过提供一个正则表达式环视检查位数字加一个.
和“TXT '
df %>% mutate(new1 = as.numeric(str_extract(test, "\\d+")), new2 = as.numeric(str_extract(test, "\\d+(?=\\.txt)"))) # test value new1 new2 #1 test_A_1_1.txt 0.51 1 1 #2 test_A_2_1.txt 0.52 2 1 #3 test_A_3_1.txt 0.56 3 1
稍微修改您现有的代码:
df %>% mutate(new = as.integer(str_extract(test, "[0-9]+")))
或者简单地
df$new <- as.integer(str_extract(df$test, "[0-9]+"))