R의 데이터 프레임에서 문자열에서 숫자를 추출하고 새 열에 배치하는 방법은 무엇입니까?




dataframe (4)

간단한 데이터 프레임이 있습니다.

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])

그러나 이것은 열 번호가 1 new 열로 이어집니다. 내가 뭘 잘못하고 있죠?


기존 코드를 약간 수정 :

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

또는 단순히

df$new <- as.integer(str_extract(df$test, "[0-9]+"))

너비가 고정되어 있다면 다음을 할 수 있습니다.

df$new <- substr(df$test, 8, 8) %>% as.integer

부동 소수점이 아닌 정수로 작업하기 때문에 as.integer 대신 as.integer 사용하는 것이 좋습니다.


왜 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

편집하다.

user @ camille의 answer 에서 문자열이 다른 숫자의 숫자를 가질 수있는 예를 보면, 여기에 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의 문제와 관련하여 str_extract_all ( list 을 반환)에서 첫 번째 list 요소 ( [[1]] ) 만 선택합니다. 대신 하나 이상의 숫자 ( \\d+ )의 첫 번째 인스턴스 만 추출해야하므로 str_extract 를 사용하는 것이 좋습니다.

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

str_extract_all ( str_extract_all 에서 출력을 얻으려면 listvectoras.numeric 다음 해당 vector as.numeric 을 적용합니다.

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

인스턴스가 여러 개인 경우 map list 요소를 반복하여 numeric 로 변환 한 다음 list 으로 유지합니다.

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 할 경우 첫 번째 str_extractstr_extract 및 마지막 stri_extract_last ( stri_extract_last - stringi 에서도 사용할 수 있음)로 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






dataframe