Wyodrębnianie liczb z wektorów łańcuchów


103

Mam taki ciąg:

years<-c("20 years old", "1 years old")

Chciałbym zebrać tylko liczbę liczbową z tego wektora. Oczekiwanym wynikiem jest wektor:

c(20, 1)

Jak mam to zrobić?

Odpowiedzi:


87

Co powiesz na

# pattern is by finding a set of numbers in the start and capturing them
as.numeric(gsub("([0-9]+).*$", "\\1", years))

lub

# pattern is to just remove _years_old
as.numeric(gsub(" years old", "", years))

lub

# split by space, get the element in first index
as.numeric(sapply(strsplit(years, " "), "[[", 1))

1
Dlaczego jest to .*konieczne? Jeśli chcesz je mieć na początku, dlaczego nie użyć ^[[:digit:]]+?
sebastian-c

2
.*jest konieczne, ponieważ musisz dopasować cały ciąg. Bez tego nic nie zostanie usunięte. Zwróć też uwagę, że submożna tego użyć zamiast gsub.
Matthew Lundberg

14
jeśli liczba nie musi znajdować się na początku ciągu, użyj tego:gsub(".*?([0-9]+).*", "\\1", years)
TMS

Chcę otrzymać 27. Nie rozumiem dlaczego, dodając warunki (np. Dodając znak „-” ze znakiem ucieczki, wynik jest dłuższy… gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Wynik: [1] „2730” gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Wynik: [1] „27 czerwca –30 ”
Lionel Trebuchon

66

Myślę, że podstawienie jest pośrednim sposobem dojścia do rozwiązania. Jeśli chcesz odzyskać wszystkie numery, polecam gregexpr:

matches <- regmatches(years, gregexpr("[[:digit:]]+", years))
as.numeric(unlist(matches))

Jeśli masz wiele dopasowań w ciągu, otrzymasz je wszystkie. Jeśli interesuje Cię tylko pierwsze dopasowanie, użyj regexprzamiast gregexpri możesz pominąć unlist.


1
Nie spodziewałem się tego, ale to rozwiązanie jest wolniejsze niż inne, o rząd wielkości.
Matthew Lundberg

@MatthewLundberg gregexpr, regexprczy jedno i drugie?
sebastian-c

1
gregexpr. Nie próbowałem regexpraż do teraz. Duża różnica. Użycie regexprstawia go pomiędzy rozwiązaniami Andrew i Aruna (drugi najszybszy) w zestawie 1e6. Być może również interesujące, użycie subw rozwiązaniu Andrew nie poprawia szybkości.
Matthew Lundberg

Dzieli się na podstawie miejsc dziesiętnych. Na przykład 2,5 staje się c ('2', '5')
MBorg

66

Aktualizacja Ponieważ extract_numericjest przestarzała, możemy użyć parse_numberz readrpakietu.

library(readr)
parse_number(years)

Oto inna opcja z extract_numeric

library(tidyr)
extract_numeric(years)
#[1] 20  1

2
W porządku dla tej aplikacji, ale pamiętaj, parse_numberże nie gra z liczbami ujemnymi. Spróbuj parse_number("–27,633")
Pokrzywa

@Nettle Tak, zgadza się i nie zadziała, jeśli jest również wiele instancji
akrun,

3
Naprawiono błąd parsowania liczb ujemnych: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde

35

Oto alternatywa dla pierwszego rozwiązania Arun, z prostszym wyrażeniem regularnym podobnym do Perla:

as.numeric(gsub("[^\\d]+", "", years, perl=TRUE))

as.numeric(sub("\\D+","",years)). Jeśli były listy przed i | lub po, togsub
Onyambu

21

Lub po prostu:

as.numeric(gsub("\\D", "", years))
# [1] 20  1

19

Rozwiązanie stringrrurociągowe:

library(stringr)
years %>% str_match_all("[0-9]+") %>% unlist %>% as.numeric

Dzięki Joe, ale ta odpowiedź nie wyodrębnia znaków ujemnych przed liczbami w ciągu.
Miao Cai

16

Ty też możesz pozbyć się wszystkich liter:

as.numeric(gsub("[[:alpha:]]", "", years))

Prawdopodobnie jest to jednak mniej generalizowalne.


3
Co dziwne, rozwiązanie Andrew przewyższa to pięciokrotnie na moim komputerze.
Matthew Lundberg

5

Wyodrębnij liczby z dowolnego ciągu na pozycji początkowej.

x <- gregexpr("^[0-9]+", years)  # Numbers with any number of digits
x2 <- as.numeric(unlist(regmatches(years, x)))

Wyodrębnij liczby z dowolnego ciągu NIEZALEŻNEGO od pozycji.

x <- gregexpr("[0-9]+", years)  # Numbers with any number of digits
x2 <- as.numeric(unlist(regmatches(years, x)))

4

Możemy również użyć str_extractfromstringr

years<-c("20 years old", "1 years old")
as.integer(stringr::str_extract(years, "\\d+"))
#[1] 20  1

Jeśli w ciągu znajduje się wiele liczb i chcemy wyodrębnić je wszystkie, możemy użyć funkcji, str_extract_allktóra w przeciwieństwie do str_extractzwraca wszystkie makty.

years<-c("20 years old and 21", "1 years old")
stringr::str_extract(years, "\\d+")
#[1] "20"  "1"

stringr::str_extract_all(years, "\\d+")

#[[1]]
#[1] "20" "21"

#[[2]]
#[1] "1"


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.