Підрахуйте кількість усіх слів у рядку


82

Чи існує функція для підрахунку кількості слів у рядку? Наприклад:

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

повернути результат 7.


На основі відповіді @ Martin нижче я створив функцію countwordpersentence.R, яка підраховує кількість слів на речення у даному текстовому рядку. Для довгого тексту, що містить кілька речень, він буде враховувати слова у всіх них і виводити середню кількість слів на речення та загальну кількість слів.
Paul Rougieux

1
str_count (temp $ question1, "") +1 було б легко, якби ви знали, що кожне слово розділено пробілом. Він знаходиться під бібліотекою stringr.
Вівек Шрівастава

Відповіді:


24

Ви можете використовувати strsplitі sapplyфункції

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

2
Просто оновлення, що тепер ви можете використовувати дещо нову lengthsфункцію в основі R, яка знаходить довжину кожного елемента:lengths(strsplot(str, " "))
Нік Тірні

це дуже добре, проблема полягає в тому, що у вас є щось на кшталт "слово, слово, слово"; у такому випадку воно повернеться 1
Dimitrios Zacharatos

71

Використовуйте символ регулярного виразу \\Wдля відповідності несловним символам, використовуючи +для позначення одного або декількох підряд, а також gregexprдля пошуку всіх збігів у рядку. Слова - це кількість роздільників слів плюс 1.

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

Це буде терпіти невдачі з порожніми рядками на початку або в кінці вектора символів, коли «слово» не задовольняє \\W«s поняття несловообразующего (один може працювати з іншими регулярними виразами \\S+, [[:alpha:]]і т.д., але там завжди буде будь-які крайні випадки з підходом регулярного виразу) тощо. Це, швидше за все, ефективніше, ніж strsplitрішення, які виділять пам’ять для кожного слова. Регулярні вирази описані в ?regex.

Оновлення Як зазначено в коментарях та в іншій відповіді @Andri, підхід зазнає невдачі із (нульовими) та однословними рядками, а також із завершальною пунктуацією

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

Багато інших відповідей також не дають результатів у цих чи подібних (наприклад, пробілах) випадках. Думаю, застереження моєї відповіді щодо „поняття одного слова” в оригінальній відповіді охоплює проблеми з розділовими знаками (рішення: виберіть інший регулярний вираз, наприклад, [[:space:]]+), але нульовий і один регістр слів є проблемою; Рішення @ Andri не розрізняє нуля та одного слова. Тож застосовуючи «позитивний» підхід до пошуку слів, можна

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

Що веде до

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

Знову ж регулярний вираз може бути вдосконалений для різних понять "слово".

Мені подобається використовувати, gregexpr()оскільки це ефективно для пам'яті. Альтернативним використанням strsplit()(наприклад, @ user813966, але з регулярним виразом для розмежування слів) та використанням оригінального поняття розмежування слів є

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

Для цього потрібно виділити нову пам’ять для кожного створеного слова та для проміжного списку слів. Це може бути відносно дорого, коли дані "великі", але, мабуть, це ефективно і зрозуміло для більшості цілей.


str1 <- c('s ss sss ss', "asdf asd hello this is your life!"); sapply(gregexpr("\\W+", str1), length) + 1повертається 4і 8. Перший правильний, другий занадто багато. Я думаю, це підрахунок пунктуації.
Френсіс Смарт

Я думаю, це підрахунок пунктуації в кінці речення. Практично впевнений, що ви хочете сказати регулярному виразу ігнорувати початкові та кінцеві збіги (вибачте, нічого доброго з цим я б не виправив сам).
Френсіс Смарт

sapply(gregexpr("\\W+", "word"), length) + 1повертає 2
jaycode

Дякую @fsmart - я думаю, що стурбованість пунктуацією висвітлюється застереженням про "поняття неслова" в оригінальній відповіді. Я оновив відповідь.
Мартін Морган,

Завдяки @jaycode, неможливість підрахувати 1 (або нуль) введення слів є проблемою. Я оновив оригінальну відповідь.
Мартін Морган,

49

Найпростіший спосіб :

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

... підрахунок усіх послідовностей на непробільних символах ( \\S+).

Але як щодо маленької функції, яка дозволяє нам також вирішити, який тип слів ми хотіли б порахувати, а який також працює на цілі вектори ?

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

Я використовую str_countфункцію з stringrбібліотеки з послідовністю екрану, \wяка представляє:

будь-який символ слова (буква, цифра або підкреслення в поточній мові: у режимі UTF-8 враховуються лише букви та цифри ASCII)

Приклад:

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

З усіх інших 9 відповідей, які мені вдалося протестувати, лише дві (від Вінсента Зонекінда та петермайснера) працювали на всі вкладені тут матеріали, але вони також вимагають stringr .

Але лише це рішення працює з усіма представленими на сьогодні входами, а також такими, як "foo+bar+baz~spam+eggs"або"Combien de mots sont dans cette phrase ?" .

Тест:

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

Вихід:

6 10 10  8  9  9  7  6  6 11

Цей підхід чудовий, але одна проблема, з якою я все ще стикаюся, полягає в тому, що він подвійно підраховує слова, що містять апостроф (наприклад, "Я" або "Джон"). Чи є спосіб вирішити це?
Тредольсен

2
@Thredolsen, якщо ви впевнені, що не буде апострофів, які слід розглядати як роздільники слів, ви можете використовувати клас символів '[\\w\']+'(не можете перевірити його, тому може застосовуватися xkcd.com/1638 ), інакше я не впевнений, що регулярний вираз є достатньо потужним, щоб впоратись із ним загалом :)
arekolek

1
Не впевнений, чи це правильне припущення, але якщо після апострофа завжди є лише одна чи дві букви, то це '\\w+(\'\\w{1,2})?'може бути хорошим рішенням.
arekolek

Дякую. Обидва підходи працюють здебільшого, але '[\\ w \'] + 'виявляється кращим у моєму випадку, оскільки деякі слова містять більше 2 символів після апострофа (наприклад: годинник). Пов’язане наступне запитання: чи є спосіб виключити випадки, коли перед двокрапкою слідує безпосередньо числовий символ (наприклад, підрахувати «10: 15» як одне слово, а не два)?
Тредольсен

2
У цьому коментарі я буду використовувати звичайний синтаксис регулярних виразів, тому приклади потребуватимуть додаткових зворотних скісних рисок. Щоб охопити такі слова, як o'clockі friggin'ви могли б це зробити \w+('\w*)?(я не знаю, чи є слова, які починаються з апострофа?). Щоб додатково обробляти години, ви можете спробувати зіставити їх як \d?\d:\d\d|\w+('\w*)?щось або зробити щось ще більш складне залежно від ваших потреб. Але це все менше про R і більше про те, як ви визначаєте слово, тож, можливо, ви можете опублікувати окреме запитання, щоб охопити ваші конкретні потреби?
arekolek

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

gsub(' {2,}',' ',str1) переконується все слова поділяються лише одним пропуском, шляхом заміни всіх входжень двох або більше пробілів одним пропуском.

strsplit(str,' ')Розділяє пропозицію в кожному просторі і повертає результат у вигляді списку. [[1]]Вистачає вектор слів з цього списку. lengthПідраховує , скільки слів.

> 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

А як щодо вкладок, нових рядків чи нерозбивних пробілів?
bartektartanus

Шлях до воскрешення 5-річної відповіді! Використовуйте '\ s' (у R, '\\ s'), щоб включити будь-який пробіл, а не ''.
mathematical.coffee

Я отримав повідомлення про свою відповідь і подивився на інших, щоб трохи їх покращити: D Не гнівайтесь! :) PS. Я теж люблю математику та каву!
bartektartanus

13

Ви можете використовувати str_match_allрегулярний вираз, який би ідентифікував ваші слова. Наступні роботи з початковим, кінцевим та дубльованими пробілами.

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

Спробуйте цю функцію з stringiпакета

   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
@bartektartanust, це якась приємна функціональність!
Джон

5
Дякую :) Перевірте решту функцій цього пакету! Впевнений, ви знайдете щось цікаве :) Будь-які коментарі вітаються!
bartektartanus

7

Ви можете використовувати функцію wc в бібліотеці qdap :

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

6

Ви можете видалити подвійні пробіли і підрахувати кількість " "у рядку, щоб отримати кількість слів. Використовуйте stringr та rm_white{ qdapRegex }

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


5

Також з stringiпакета, функція прямого руху впередstri_count_words

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

4

Рішення 7 не дає правильного результату, якщо є лише одне слово. Вам слід не просто підрахувати елементи в результаті gregexpr (а це -1, якщо там, де не збігається), а підрахувати елементи> 0.

Ерго:

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

Це все одно матиме проблеми, якщо str1починається або закінчується символами, що не містять слів. Якщо це викликає занепокоєння, ця версія буде шукати лише пробіли між словами:sapply(gregexpr("\\b\\W+\\b", str, perl=TRUE), function(x) sum(x>0) ) + 1
Адам Бредлі

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

буде добре з подвійними / потрійними пробілами між словами

Усі інші відповіді мають проблеми з кількома пробілами між словами.


2

вимагати (stringr)

Визначте дуже просту функцію

str_words <- function(sentence) {

  str_count(sentence, " ") + 1

}

Перевірте

str_words(This is a sentence with six words)

1

Використовуйте nchar

якщо викликається вектор рядків x

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

Знайдіть кількість пробілів, а потім додайте один


1

Я знайшов наступну функцію та регулярний вираз корисними для підрахунку слів, особливо при роботі з одинарними та подвійними дефісами, де перші, як правило, не повинні вважатися розривом слів, наприклад, добре відомий, hi-fi; тоді як подвійний дефіс є розділовим знаком, який не обмежений пробілами - наприклад, для думок у дужках.

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 - це корисний пакет. Але в цьому прикладі він перелічує слова через дефіс.

stringi::stri_count_words(txt) #11 words

0

За допомогою stringr пакета можна також написати простий скрипт, який міг би пройти вектор рядків, наприклад, через цикл for.

Скажімо

df $ текст

містить вектор рядків, які нам цікаво проаналізувати. Спочатку ми додаємо додаткові стовпці до існуючого фрейму даних df, як показано нижче:

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

Потім запускаємо цикл for над вектором рядків, як показано нижче:

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
}

Отримані стовпці: рядки та символ будуть містити кількість слів та символів, і це буде досягнуто одним рухом для вектора рядків.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.