如何从R的数据框中的字符串中提取数字并将其放置在新列中?

use*_*544 4 r dataframe

我有一个简单的数据框:

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
Run Code Online (Sandbox Code Playgroud)

预期产量

我想将数字复制到第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
Run Code Online (Sandbox Code Playgroud)

尝试

使用以下代码,我可以从字符串中提取数字:

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
Run Code Online (Sandbox Code Playgroud)

我想将此代码应用于第一列的所有值:

library(tidyverse)
df %>% mutate(new = as.numeric(str_extract_all(df$test, "[0-9]+")[[1]])[1])
Run Code Online (Sandbox Code Playgroud)

但是,这导致new只有数字的列1。我究竟做错了什么?

Rui*_*das 7

为什么不使用基础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
Run Code Online (Sandbox Code Playgroud)

编辑。

按照用户@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)
Run Code Online (Sandbox Code Playgroud)


akr*_*run 6

我们可以使用parse_number从readr

library(dplyr)
library(purrr)
library(stringr)
df %>%
    mutate(new = readr::parse_number(as.character(test)))
Run Code Online (Sandbox Code Playgroud)

关于OP的问题,它仅从中选择第一个list元素([[1]])str_extract_all(返回list)。相反,最好使用,str_extract因为我们只需要提取一个或多个数字(\\d+)的第一个实例

df %>%
    mutate(new = as.numeric(str_extract(test, "[0-9]+")))
Run Code Online (Sandbox Code Playgroud)

如果我们需要从得到的输出str_extract_all(万一),unlist将list到vector,然后应用as.numeric上vector

df %>%
     mutate(new = as.numeric(unlist(str_extract_all(test, "[0-9]+"))))
Run Code Online (Sandbox Code Playgroud)

如果有多个实例,则它保持为list转换成之后numeric通过经循环list与元件map

df %>% 
     mutate(new = map(str_extract_all(test, "[0-9]+"), as.numeric))
Run Code Online (Sandbox Code Playgroud)

注意:str_extract基于解决方案首先发布在这里。


在中base R,我们可以使用regexpr

df$new <- as.numeric(regmatches(df$test, regexpr("\\d+", df$test)))
Run Code Online (Sandbox Code Playgroud)

更新资料

随着更新的例子,如果我们需要得到的数字的两个实例,第一个可以与提取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
Run Code Online (Sandbox Code Playgroud)


sin*_*dur 6

稍微修改您现有的代码:

df %>% 
  mutate(new = as.integer(str_extract(test, "[0-9]+")))
Run Code Online (Sandbox Code Playgroud)

或者简单地

df$new <- as.integer(str_extract(df$test, "[0-9]+"))
Run Code Online (Sandbox Code Playgroud)