Zahlen aus Vektoren von Strings extrahieren


100

Ich habe eine Zeichenfolge wie diese:

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

Ich möchte nur die numerische Zahl aus diesem Vektor erfassen. Die erwartete Ausgabe ist ein Vektor:

c(20, 1)

Wie mache ich das?

Antworten:


82

Wie wäre es mit

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

oder

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

oder

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

1
Warum ist das .*notwendig? Wenn Sie sie am Anfang haben möchten, warum nicht verwenden ^[[:digit:]]+?
Sebastian-c

2
.*ist erforderlich, da Sie die gesamte Zeichenfolge abgleichen müssen. Ohne das wird nichts entfernt. Beachten Sie auch, dass subhier anstelle von verwendet werden kann gsub.
Matthew Lundberg

12
Wenn die Nummer nicht am Anfang der Zeichenfolge stehen muss, verwenden Sie Folgendes:gsub(".*?([0-9]+).*", "\\1", years)
TMS

Ich möchte 27 erhalten. Ich verstehe nicht, warum durch Hinzufügen von Bedingungen (z. B. Hinzufügen eines maskierten "-") das Ergebnis länger wird ... gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Ergebnis: [1] "2730" gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Ergebnis: [1] "27. Juni –30 "
Lionel Trebuchon

64

Ich denke, dass Substitution ein indirekter Weg ist, um zur Lösung zu gelangen. Wenn Sie alle Nummern abrufen möchten, empfehle ich gregexpr:

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

Wenn Sie mehrere Übereinstimmungen in einer Zeichenfolge haben, werden alle diese erhalten. Wenn Sie nur am ersten Spiel interessiert sind, verwenden Sie regexprstattdessen gregexprund Sie können das überspringen unlist.


1
Ich habe es nicht erwartet, aber diese Lösung ist um eine Größenordnung langsamer als jede andere.
Matthew Lundberg

@MatthewLundberg das gregexpr, regexproder beides?
Sebastian-c

1
gregexpr. Ich hatte es regexprbis jetzt nicht versucht . RIESIGER Unterschied. Mit regexprsetzt es zwischen Andrews und Aruns Lösungen (zweitschnellste) auf einem 1e6-Set. Vielleicht auch interessant, die Verwendung subin Andrews Lösung verbessert die Geschwindigkeit nicht.
Matthew Lundberg

Dies wird basierend auf Dezimalstellen aufgeteilt. Zum Beispiel wird 2.5 zu c ('2', '5')
MBorg

64

Update Da extract_numericveraltet ist, können wir parse_numberaus readrPaket verwenden.

library(readr)
parse_number(years)

Hier ist eine weitere Option mit extract_numeric

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

2
Gut für diese Anwendung, aber denken Sie daran, parse_numberspielt nicht mit negativen Zahlen. Versuchen Sie parse_number("–27,633")
Brennnessel

@Nettle Ja, das ist richtig und es wird nicht funktionieren, wenn es auch mehrere Instanzen gibt
akrun

3
Der Fehler beim Parsen negativer Zahlen wurde behoben: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde

35

Hier ist eine Alternative zu Aruns erster Lösung mit einem einfacheren Perl-ähnlichen regulären Ausdruck:

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

as.numeric(sub("\\D+","",years)). Wenn es vorher und nachher Briefe gab, danngsub
Onyambu

21

Oder einfach:

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

19

Eine stringrPipeline-Lösung:

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

Danke Joe, aber diese Antwort extrahiert nicht die negativen Vorzeichen vor den Zahlen in der Zeichenfolge.
Miao Cai

16

Sie könnten auch alle Buchstaben loswerden:

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

Wahrscheinlich ist dies jedoch weniger verallgemeinerbar.


3
Seltsamerweise übertrifft Andrews Lösung dies auf meinem Computer um den Faktor 5.
Matthew Lundberg

5

Extrahieren Sie Zahlen aus einer beliebigen Zeichenfolge an der Anfangsposition.

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

Extrahieren Sie Zahlen aus einer beliebigen Zeichenfolge, die von der Position UNABHÄNGIG ist.

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

4

Wir können auch str_extractvon verwendenstringr

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

Wenn die Zeichenfolge mehrere Zahlen enthält und wir alle extrahieren möchten, können wir verwenden, str_extract_alldie im Gegensatz zu str_extractallen Zahlen alle Macthes zurückgeben.

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"

2

Nach dem Beitrag von Gabor Grothendieck auf der R-Hilfe-Mailingliste

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

library(gsubfn)
pat <- "[-+.e0-9]*\\d"
sapply(years, function(x) strapply(x, pat, as.numeric)[[1]])

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.