Policz liczbę wszystkich słów w ciągu


82

Czy istnieje funkcja licząca liczbę słów w ciągu? Na przykład:

str1 <- "How many words are in this sentence"

aby zwrócić wynik 7.


Na podstawie poniższej odpowiedzi @ Martina stworzyłem funkcję countwordpersentence.R, która zlicza liczbę słów w zdaniu w danym ciągu tekstowym. W przypadku długiego tekstu zawierającego kilka zdań policzy słowa we wszystkich i wyświetli średnią liczbę słów w zdaniu oraz całkowitą liczbę słów.
— Paul Rougieux

1
str_count (temp $ question1, "") +1 byłoby łatwe, gdybyś wiedział, że każde słowo jest oddzielone spacją. Znajduje się w bibliotece stringr.
— Vivek Srivastava

Odpowiedzi:


24

Możesz używać strspliti sapplyfunkcji

sapply(strsplit(str1, " "), length)

2
Tylko aktualizacja, że ​​możesz teraz użyć nieco nowej lengthsfunkcji w bazie R, która znajduje długość każdego elementu:lengths(strsplot(str, " "))
— Nick Tierney

to bardzo dobrze problem jest, gdy masz coś takiego jak „słowo, słowo, słowo” w takim przypadku zwróci 1
— Dimitrios Zacharatos

71

Użyj symbolu wyrażenia regularnego, \\Waby dopasować znaki niebędące słowami, użyj, +aby wskazać jeden lub więcej w wierszu, a także, gregexpraby znaleźć wszystkie dopasowania w ciągu. Słowa to liczba separatorów słów plus 1.

lengths(gregexpr("\\W+", str1)) + 1

To nie z pustymi strunami na początku lub na końcu wektora znaków, gdy „Słowo” nie spełnia \\W„s pojęcie nie-słowa (można pracować z innych wyrażeń regularnych \\S+, [[:alpha:]]itp, ale nie będzie zawsze być skrajnymi przypadkami z podejściem regex), itp. Prawdopodobnie jest bardziej wydajne niż strsplitrozwiązania, które przydzielą pamięć dla każdego słowa. Wyrażenia regularne opisano w ?regex.

Aktualizacja Jak zauważono w komentarzach i w innej odpowiedzi @Andri, podejście kończy się niepowodzeniem z ciągami (zero) i jednowyrazowymi oraz z końcową interpunkcją

str1 = c("", "x", "x y", "x y!" , "x y! z")
lengths(gregexpr("[A-z]\\W+", str1)) + 1L
# [1] 2 2 2 3 3

Wiele innych odpowiedzi również zawodzi w tych lub podobnych przypadkach (np. Wiele spacji). Myślę, że moje zastrzeżenie dotyczące „pojęcia jednego słowa” w pierwotnej odpowiedzi obejmuje problemy z interpunkcją (rozwiązanie: wybierz inne wyrażenie regularne, np. [[:space:]]+), Ale problemem są przypadki z zerami i jednym słowem; Rozwiązanie @ Andri nie rozróżnia między zerem a jednym słowem. Można więc przyjąć „pozytywne” podejście do znajdowania słów

sapply(gregexpr("[[:alpha:]]+", str1), function(x) sum(x > 0))

Prowadzący do

sapply(gregexpr("[[:alpha:]]+", str1), function(x) sum(x > 0))
# [1] 0 1 2 2 3

Ponownie wyrażenie regularne można by udoskonalić pod kątem różnych pojęć „słowo”.

Podoba mi się użycie, gregexpr()ponieważ jest wydajne pod względem pamięci. Alternatywą jest używanie strsplit()(jak @ user813966, ale z wyrażeniem regularnym do oddzielania słów) i używanie oryginalnego pojęcia rozdzielania słów

lengths(strsplit(str1, "\\W+"))
# [1] 0 1 2 2 3

To wymaga przydzielenia nowej pamięci dla każdego tworzonego słowa i dla pośredniej listy słów. Może to być stosunkowo kosztowne, gdy dane są „duże”, ale prawdopodobnie jest skuteczne i zrozumiałe w większości zastosowań.


str1 <- c('s ss sss ss', "asdf asd hello this is your life!"); sapply(gregexpr("\\W+", str1), length) + 1zwroty 4i 8. Pierwsza poprawna, druga za dużo. Myślę, że liczy się interpunkcja.
— Francis Smart

Myślę, że liczy interpunkcję na końcu zdania. Całkiem pewny, że chciałbyś powiedzieć regex, aby ignorował dopasowania początkowe i końcowe (przepraszam, nie jest to dobre, bo sam bym to naprawił).
— Francis Smart

sapply(gregexpr("\\W+", "word"), length) + 1zwraca 2
— kod jaycode

Dzięki @fsmart - myślę, że obawy dotyczące interpunkcji są objęte zastrzeżeniem dotyczącym „pojęcia braku wyrazu” w oryginalnej odpowiedzi. Zaktualizowałem odpowiedź.
— Martin Morgan

Dzięki @jaycode, brak możliwości zliczenia 1 (lub zera) słów jest problemem. Zaktualizowałem oryginalną odpowiedź.
— Martin Morgan

49

Najprostszy sposób to:

require(stringr)
str_count("one,   two three 4,,,, 5 6", "\\S+")

... licząc wszystkie sekwencje na znaki inne niż spacje ( \\S+).

Ale co z małą funkcją, która pozwala nam również zdecydować, które rodzaje słów chcielibyśmy policzyć i która działa również na całych wektorach ?

require(stringr)
nwords <- function(string, pseudo=F){
  ifelse( pseudo, 
          pattern <- "\\S+", 
          pattern <- "[[:alpha:]]+" 
        )
  str_count(string, pattern)
}

nwords("one,   two three 4,,,, 5 6")
# 3

nwords("one,   two three 4,,,, 5 6", pseudo=T)
# 6

37

Używam str_countfunkcji z stringrbiblioteki z sekwencją ucieczki, \wktóra reprezentuje:

dowolny znak `` słowa '' (litera, cyfra lub podkreślenie w bieżącym języku: w trybie UTF-8 uwzględniane są tylko litery i cyfry ASCII)

Przykład:

> str_count("How many words are in this sentence", '\\w+')
[1] 7

Ze wszystkich pozostałych 9 odpowiedzi, które udało mi się przetestować, tylko dwie (autorstwa Vincenta Zoonekynda i Petermeissnera) działały dla wszystkich przedstawionych dotychczas danych wejściowych, ale one również wymagają stringr.

Ale tylko to rozwiązanie działa ze wszystkimi dotychczas przedstawionymi danymi wejściowymi oraz wejściami takimi jak "foo+bar+baz~spam+eggs"lub "Combien de mots sont dans cette phrase ?".

Reper:

library(stringr)

questions <-
  c(
    "", "x", "x y", "x y!", "x y! z",
    "foo+bar+baz~spam+eggs",
    "one,   two three 4,,,, 5 6",
    "How many words are in this sentence",
    "How  many words    are in this   sentence",
    "Combien de mots sont dans cette phrase ?",
    "
    Day after day, day after day,
    We stuck, nor breath nor motion;
    "
  )

answers <- c(0, 1, 2, 2, 3, 5, 6, 7, 7, 7, 12)

score <- function(f) sum(unlist(lapply(questions, f)) == answers)

funs <-
  c(
    function(s) sapply(gregexpr("\\W+", s), length) + 1,
    function(s) sapply(gregexpr("[[:alpha:]]+", s), function(x) sum(x > 0)),
    function(s) vapply(strsplit(s, "\\W+"), length, integer(1)),
    function(s) length(strsplit(gsub(' {2,}', ' ', s), ' ')[[1]]),
    function(s) length(str_match_all(s, "\\S+")[[1]]),
    function(s) str_count(s, "\\S+"),
    function(s) sapply(gregexpr("\\W+", s), function(x) sum(x > 0)) + 1,
    function(s) length(unlist(strsplit(s," "))),
    function(s) sapply(strsplit(s, " "), length),
    function(s) str_count(s, '\\w+')
  )

unlist(lapply(funs, score))

Wynik:

6 10 10  8  9  9  7  6  6 11

To podejście jest doskonałe, ale wciąż napotykam na to, że podwójnie liczy słowa, które zawierają apostrof (np. „Jestem” lub „Jana”). Czy jest jakiś sposób na rozwiązanie tego problemu?
— Thredolsen

2
@ Thredolsen, jeśli jesteś pewien, że nie będzie apostrofów, które powinny być traktowane jako separatory słów, możesz użyć klasy znaków '[\\w\']+'(nie można tego przetestować, więc xkcd.com/1638 może mieć zastosowanie), w przeciwnym razie nie jestem pewien, czy regex jest wystarczająco potężny, aby sobie z tym poradzić w ogólnym przypadku :)
— arekolek

1
Nie jestem pewien, czy to dobre założenie, ale jeśli po apostrofie zawsze jest tylko jedna lub dwie litery, '\\w+(\'\\w{1,2})?'może to być dobre rozwiązanie.
— arekolek

Dziękuję Ci. Oba podejścia działają w większości, ale „[\\ w \ '] +” wydaje się być lepsze w moim przypadku, ponieważ niektóre słowa zawierają więcej niż 2 znaki po apostrofie (np. Godzina). Powiązane pytanie uzupełniające: czy istnieje sposób, aby wykluczyć również przypadki, w których po dwukropku występuje bezpośrednio znak numeryczny (np. Licz „10:15” jako jedno słowo, a nie dwa)?
— Thredolsen

2
W tym komentarzu będę używał zwykłej składni wyrażeń regularnych, więc przykłady będą wymagały dodatkowych ukośników odwrotnych. Aby zakryć słowa takie jak o'clocki friggin'możesz to zrobić \w+('\w*)?(nie wiem, czy są słowa zaczynające się od apostrofu?). Aby dodatkowo obsłużyć godziny, możesz spróbować je dopasować \d?\d:\d\d|\w+('\w*)?lub zrobić coś jeszcze bardziej skomplikowanego w zależności od potrzeb. Ale coraz mniej dotyczy to języka R, a więcej dotyczy tego, jak definiujesz słowo, więc może możesz zadać osobne pytanie, aby zaspokoić swoje konkretne potrzeby?
— arekolek

15
str2 <- gsub(' {2,}',' ',str1)
length(strsplit(str2,' ')[[1]])

Te gsub(' {2,}',' ',str1)marki, że wszystkie słowa są oddzielone tylko jednej przestrzeni, poprzez zastąpienie wszystkich wystąpień dwóch lub więcej pomieszczeń z jednego miejsca.

strsplit(str,' ')Dzieli zdanie w każdej przestrzeni i zwraca wynik w postaci listy. [[1]]Chwyta wektor słów z tej listy. lengthLiczy się jak najwięcej słów.

> str1 <- "How many words are in this     sentence"
> str2 <- gsub(' {2,}',' ',str1)
> str2
[1] "How many words are in this sentence"
> strsplit(str2,' ')
[[1]]
[1] "How"      "many"     "words"    "are"      "in"       "this"     "sentence"
> strsplit(str2,' ')[[1]]
[1] "How"      "many"     "words"    "are"      "in"       "this"     "sentence"
> length(strsplit(str2,' ')[[1]])
[1] 7

A co z tabulatorami, nowymi liniami lub nierozerwalnymi spacjami?
— bartektartanus,

Sposób na wskrzeszenie 5-letniej odpowiedzi! Użyj '\ s' (w R, '\\ s'), aby dołączyć dowolny typ spacji zamiast ''.
— mathematical.coffee

Otrzymałem powiadomienie o mojej odpowiedzi i spojrzałem na innych, aby je nieco poprawić: D Nie wściekaj się! :) PS. Lubię też matematykę i kawę!
— bartektartanus

13

Możesz użyć str_match_all, z wyrażeniem regularnym, które identyfikowałoby twoje słowa. Poniższe informacje dotyczą spacji początkowych, końcowych i powielonych.

library(stringr)
s <-  "
  Day after day, day after day,
  We stuck, nor breath nor motion;
"
m <- str_match_all( s, "\\S+" )  # Sequences of non-spaces
length(m[[1]])

11

Wypróbuj tę funkcję z stringipakietu

   require(stringi)
   > s <- c("Lorem ipsum dolor sit amet, consectetur adipisicing elit.",
    +        "nibh augue, suscipit a, scelerisque sed, lacinia in, mi.",
    +        "Cras vel lorem. Etiam pellentesque aliquet tellus.",
    +        "")
    > stri_stats_latex(s)
        CharsWord CharsCmdEnvir    CharsWhite         Words          Cmds        Envirs 
              133             0            30            24             0             0 

6
@bartektartanusthat to niezła funkcjonalność!
— John

5
Dziękuję :) Sprawdź pozostałe funkcje z tego pakietu! Na pewno znajdziesz coś ciekawego :) Wszelkie uwagi mile widziane!
— bartektartanus

7

Możesz użyć funkcji wc w bibliotece qdap :

> str1 <- "How many words are in this sentence"
> wc(str1)
[1] 7

6

Możesz usunąć podwójne spacje i policzyć liczbę " "w ciągu, aby uzyskać liczbę słów. Użyj stringr i rm_white{ qdapRegex }

str_count(rm_white(s), " ") +1


5

Również z stringipakietu, prosta funkcjastri_count_words

stringi::stri_count_words(str1)
#[1] 7

4

Rozwiązanie 7 nie daje prawidłowego wyniku w przypadku, gdy jest tylko jedno słowo. Powinieneś nie tylko liczyć elementy w wyniku gregexpr (czyli -1, jeśli tam, gdzie nie pasuje), ale policzyć elementy> 0.

Ergo:

sapply(gregexpr("\\W+", str1), function(x) sum(x>0) ) + 1 

Będzie to nadal powodować problemy, jeśli str1zaczyna się lub kończy znakami niebędącymi słowami. Jeśli to dotyczy, ta wersja będzie szukać tylko spacji między słowami:sapply(gregexpr("\\b\\W+\\b", str, perl=TRUE), function(x) sum(x>0) ) + 1
— Adam Bradley,

4
require(stringr)
str_count(x,"\\w+")

będzie dobrze z podwójnymi / potrójnymi odstępami między słowami

We wszystkich innych odpowiedziach występuje więcej niż jedna spacja między wyrazami.


2

wymagają (stringr)

Zdefiniuj bardzo prostą funkcję

str_words <- function(sentence) {

  str_count(sentence, " ") + 1

}

Czek

str_words(This is a sentence with six words)

1

Posługiwać się nchar

jeśli wywoływany jest wektor ciągów x

(nchar(x) - nchar(gsub(' ','',x))) + 1

Sprawdź liczbę spacji, a następnie dodaj jedną


1

Zauważyłem, że następująca funkcja i wyrażenie regularne są przydatne do liczenia słów, zwłaszcza w przypadku łączników pojedynczych i podwójnych, gdzie ta pierwsza generalnie nie powinna być liczona jako podział wyrazu, np. Dobrze znane, hi-fi; podczas gdy podwójny łącznik jest separatorem interpunkcyjnym, który nie jest ograniczony białymi znakami - na przykład w przypadku uwag w nawiasach.

txt <- "Don't you think e-mail is one word--and not two!" #10 words
words <- function(txt) { 
length(attributes(gregexpr("(\\w|\\w\\-\\w|\\w\\'\\w)+",txt)[[1]])$match.length) 
}

words(txt) #10 words

Stringi to przydatny pakiet. Jednak wyrazy w tym przykładzie są zbyt liczone z powodu łącznika.

stringi::stri_count_words(txt) #11 words

0

Ze stringr pakietu można również napisać prosty skrypt, który mógłby przejść przez wektor łańcuchów, na przykład przez pętlę for.

Powiedzmy

df $ tekst

zawiera wektor ciągów, które chcemy przeanalizować. Najpierw dodajemy dodatkowe kolumny do istniejącej ramki danych df, jak poniżej:

df$strings    = as.integer(NA)
df$characters = as.integer(NA)

Następnie uruchamiamy pętlę for na wektorze ciągów, jak poniżej:

for (i in 1:nrow(df)) 
{
   df$strings[i]    = str_count(df$text[i], '\\S+') # counts the strings
   df$characters[i] = str_count(df$text[i])         # counts the characters & spaces
}

Wynikowe kolumny: łańcuchy i znak będą zawierały liczbę słów i znaków, a zostanie to osiągnięte za jednym razem dla wektora ciągów.

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.