Đếm số lượng tất cả các từ trong một chuỗi


82

Có một chức năng để đếm số lượng từ trong một chuỗi? Ví dụ:

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

để trả về kết quả là 7.


Dựa trên câu trả lời của @ Martin bên dưới, tôi đã tạo một hàm countwordpersentence.R để đếm số từ mỗi câu trong một chuỗi văn bản nhất định. Đối với một văn bản dài có chứa nhiều câu, nó sẽ đếm các từ trong tất cả chúng và xuất ra số từ trung bình trên mỗi câu và tổng số từ.
Paul Rougieux

1
str_count (temp $ question1, "") +1 sẽ dễ dàng nếu bạn biết mỗi từ được phân tách bằng dấu cách. Nó nằm dưới thư viện stringr.
Vivek Srivastava

Câu trả lời:


22

Bạn có thể sử dụng strsplitsapplycác chức năng

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

Chỉ là một bản cập nhật mà giờ đây bạn có thể sử dụng hàm hơi mới lengthstrong cơ sở R, hàm này tìm độ dài của mỗi phần tử:lengths(strsplot(str, " "))
Nick Tierney

điều này rất tốt, vấn đề là khi bạn có một cái gì đó như "word, word, word" trong trường hợp đó nó sẽ trả về 1
Dimitrios Zacharatos

71

Sử dụng biểu tượng cụm từ thông dụng \\Wđể so khớp các ký tự không phải từ, dùng +để chỉ một hoặc nhiều trong một hàng, cùng với đó gregexprđể tìm tất cả các kết quả phù hợp trong một chuỗi. Các từ là số lượng ngăn cách từ cộng với 1.

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

Điều này sẽ thất bại với chuỗi trống ở đầu hoặc cuối của vector nhân vật, khi một "từ" không đáp ứng \\W's khái niệm phi-word (người ta có thể làm việc với các biểu thức thông thường khác, \\S+, [[:alpha:]], vv, nhưng sẽ luôn là các trường hợp cạnh với cách tiếp cận regex), v.v. Nó có thể hiệu quả hơn strsplitcác giải pháp, sẽ phân bổ bộ nhớ cho mỗi từ. Biểu thức chính quy được mô tả trong ?regex.

Cập nhật Như đã lưu ý trong các nhận xét và trong một câu trả lời khác của @Andri, cách tiếp cận không thành công với (không) và chuỗi một từ và với dấu câu ở cuối

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

Nhiều câu trả lời khác cũng không thành công trong những trường hợp này hoặc tương tự (ví dụ: nhiều khoảng trắng). Tôi nghĩ rằng câu trả lời của tôi báo trước về 'khái niệm một từ' trong câu trả lời ban đầu bao gồm các vấn đề với dấu câu (giải pháp: chọn một biểu thức chính quy khác, ví dụ [[:space:]]+:), nhưng trường hợp 0 ​​và một từ là một vấn đề; Giải pháp của @ Andri không phân biệt được giữa 0 và 1 từ. Vì vậy, thực hiện một cách tiếp cận 'tích cực' để tìm các từ mà một người có thể

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

Dẫn tới

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

Một lần nữa, biểu thức chính quy có thể được tinh chỉnh cho các khái niệm khác nhau về 'từ'.

Tôi thích việc sử dụng gregexpr()vì nó hiệu quả về bộ nhớ. Một giải pháp thay thế bằng cách sử dụng strsplit()(như @ user813966, nhưng với biểu thức chính quy để phân tách các từ) và sử dụng khái niệm ban đầu về phân tách các từ là

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

Điều này cần phân bổ bộ nhớ mới cho mỗi từ được tạo và cho danh sách các từ trung gian. Điều này có thể tương đối tốn kém khi dữ liệu 'lớn', nhưng có lẽ nó hiệu quả và dễ hiểu cho hầu hết các mục đích.


str1 <- c('s ss sss ss', "asdf asd hello this is your life!"); sapply(gregexpr("\\W+", str1), length) + 1trả lại 48. Đầu tiên đúng, thứ hai quá nhiều. Tôi nghĩ rằng nó đang đếm dấu câu.
Francis Smart

Tôi nghĩ nó đang đếm dấu chấm câu ở cuối câu. Khá chắc chắn rằng bạn sẽ muốn yêu cầu regex bỏ qua các trận đấu bắt đầu và kết thúc (xin lỗi không tốt với nó hoặc tôi sẽ tự sửa nó).
Francis Smart

sapply(gregexpr("\\W+", "word"), length) + 1trả về 2
jaycode

Cảm ơn @fsmart - Tôi nghĩ rằng mối quan tâm về dấu câu đã được đề cập trong tuyên bố từ chối trách nhiệm về 'khái niệm không phải từ' trong câu trả lời gốc. Tôi đã cập nhật câu trả lời.
Martin Morgan

Cảm ơn @jaycode, không thể đếm 1 (hoặc không) đầu vào từ là một vấn đề. Tôi đã cập nhật câu trả lời ban đầu.
Martin Morgan

47

Cách đơn giản nhất sẽ là:

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

... đếm tất cả các chuỗi trên các ký tự không phải khoảng trắng ( \\S+).

Nhưng còn một hàm nhỏ cho phép chúng ta quyết định loại từ nào chúng ta muốn đếm và hoạt động trên cả vectơ thì sao?

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

35

Tôi sử dụng str_counthàm từ stringrthư viện với trình tự thoát \wđại diện:

bất kỳ ký tự 'từ' nào (chữ cái, chữ số hoặc dấu gạch dưới trong ngôn ngữ hiện tại: ở chế độ UTF-8, chỉ các chữ cái và chữ số ASCII mới được xem xét)

Thí dụ:

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

Trong tất cả 9 câu trả lời khác mà tôi có thể kiểm tra, chỉ có hai câu (của Vincent Zoonekynd, và của petermeissner) phù hợp với tất cả các đầu vào được trình bày ở đây cho đến nay, nhưng chúng cũng yêu cầu stringr.

Nhưng chỉ giải pháp này hoạt động với tất cả các đầu vào được trình bày cho đến nay, cộng với các đầu vào như "foo+bar+baz~spam+eggs"hoặc "Combien de mots sont dans cette phrase ?".

Điểm chuẩn:

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

Đầu ra:

6 10 10  8  9  9  7  6  6 11

Cách tiếp cận này rất tuyệt vời, nhưng một vấn đề mà tôi vẫn gặp phải là nó đếm kép các từ có chứa dấu huyền (ví dụ: "Tôi" hoặc "John's"). Có cách nào để giải quyết vấn đề này?
Thredolsen

2
@Thredolsen nếu bạn chắc chắn sẽ không có dấu nháy đơn được coi là dấu phân cách từ, bạn có thể sử dụng một lớp ký tự '[\\w\']+'(không thể kiểm tra nó, vì vậy xkcd.com/1638 có thể áp dụng), nếu không, tôi không chắc liệu regex là đủ mạnh để xử lý nó trong trường hợp tổng quát :)
arekolek

1
Không chắc đó có phải là một giả định tốt hay không, nhưng nếu luôn chỉ có một hoặc hai chữ cái sau dấu nháy đơn, thì đó '\\w+(\'\\w{1,2})?'có thể là một giải pháp tốt.
arekolek

Cảm ơn bạn. Cả hai cách tiếp cận đều hoạt động trong hầu hết các phần, nhưng '[\\ w \'] + 'có vẻ tốt hơn trong trường hợp của tôi, vì một số từ chứa nhiều hơn 2 ký tự sau dấu nháy đơn (ví dụ: giờ). Câu hỏi tiếp theo liên quan: có cách nào để loại trừ trường hợp dấu hai chấm được theo sau trực tiếp bởi một ký tự số (ví dụ: đếm '10: 15 'là một từ, thay vì hai)?
Thredolsen

2
Trong nhận xét này, tôi sẽ sử dụng cú pháp regex đơn giản nên các ví dụ sẽ cần thêm một số dấu gạch chéo ngược. Để bao gồm những từ như o'clockfriggin'bạn có thể làm \w+('\w*)?(Tôi không biết liệu có những từ bắt đầu bằng dấu nháy đơn không?). Ngoài ra, để xử lý giờ, bạn có thể cố gắng khớp chúng như \d?\d:\d\d|\w+('\w*)?hoặc làm một việc gì đó thậm chí phức tạp hơn tùy thuộc vào nhu cầu của bạn. Nhưng điều này ngày càng ít về R và nhiều hơn về cách bạn định nghĩa một từ, vì vậy có thể bạn có thể đăng một câu hỏi riêng để đáp ứng nhu cầu cụ thể của mình?
arekolek

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

Các gsub(' {2,}',' ',str1)đảm bảo tất cả các từ được ngăn cách bởi chỉ có một không gian, bằng cách thay thế tất cả các lần xuất hiện của hai hay nhiều không gian với một không gian.

Phép strsplit(str,' ')tách câu ở mọi khoảng trắng và trả về kết quả trong một danh sách. Các [[1]]grabs vector các từ ra khỏi danh sách đó. Số lengthđếm lên có bao nhiêu từ.

> 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

Điều gì về tab, dòng mới hoặc dấu cách không thể ngắt?
bartektartanus

Cách để phục hồi câu trả lời cũ 5 năm! Sử dụng '\ s' (trong R, '\\ s') để bao gồm bất kỳ loại khoảng trắng nào thay vì ''.
mathematical.coffee

Tôi đã nhận được thông báo về câu trả lời của mình và hãy xem xét những người khác để cải thiện chúng một chút: D Đừng tức giận! :) Tái bút. Tôi thích toán học và cà phê quá!
bartektartanus

13

Bạn có thể sử dụng str_match_all, với một biểu thức chính quy sẽ xác định các từ của bạn. Phần sau hoạt động với các khoảng trống ban đầu, cuối cùng và các dấu cách trùng lặp.

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

Hãy thử chức năng này từ stringigói

   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 là một số chức năng hay!
John

5
Cảm ơn bạn :) Kiểm tra phần còn lại của các chức năng từ gói này! Tôi chắc rằng bạn sẽ tìm thấy một cái gì đó thú vị :) Mọi ý kiến ​​đều được hoan nghênh!
bartektartanus

7

Bạn có thể sử dụng hàm wc trong thư viện qdap :

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

6

Bạn có thể loại bỏ khoảng trắng kép và đếm số lượng " "trong chuỗi để có được số lượng từ. Sử dụng stringrrm_white{ qdapRegex }

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


5

Cũng từ stringigói, chức năng chuyển tiếp thẳngstri_count_words

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

4

Giải pháp 7 không đưa ra kết quả chính xác trong trường hợp chỉ có một từ. Bạn không nên chỉ đếm các phần tử trong kết quả của gregexpr (là -1 nếu ở đó không khớp) mà hãy đếm các phần tử> 0.

Ergo:

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

Điều này vẫn sẽ có vấn đề nếu str1bắt đầu hoặc kết thúc bằng các ký tự không phải từ. Nếu đó là một mối quan tâm, phiên bản này sẽ chỉ tìm kiếm khoảng trống giữa chữ:sapply(gregexpr("\\b\\W+\\b", str, perl=TRUE), function(x) sum(x>0) ) + 1
Adam Bradley

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

sẽ ổn với khoảng trắng đôi / ba giữa các từ

Tất cả các câu trả lời khác đều có vấn đề với nhiều hơn một khoảng trắng giữa các từ.


2

yêu cầu (stringr)

Xác định một chức năng rất đơn giản

str_words <- function(sentence) {

  str_count(sentence, " ") + 1

}

Kiểm tra

str_words(This is a sentence with six words)

1

Sử dụng nchar

nếu vectơ của chuỗi được gọi là x

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

Tìm ra số lượng khoảng trắng sau đó thêm một


1

Tôi đã tìm thấy hàm sau và regex hữu ích cho việc đếm từ, đặc biệt là trong việc xử lý dấu gạch nối đơn so với dấu gạch nối kép, trong đó dấu gạch ngang trước đây thường không được tính là ngắt từ, ví dụ: nổi tiếng, hi-fi; trong khi dấu gạch ngang kép là dấu phân cách dấu câu không bị giới hạn bởi khoảng trắng - chẳng hạn như đối với nhận xét trong ngoặc đơn.

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 là một gói hữu ích. Nhưng nó đếm quá số từ trong ví dụ này do dấu gạch nối.

stringi::stri_count_words(txt) #11 words

0

Với gói stringr , người ta cũng có thể viết một tập lệnh đơn giản có thể duyệt một vectơ chuỗi chẳng hạn thông qua vòng lặp for.

Hãy cùng nói nào

df $ text

chứa một vectơ của các chuỗi mà chúng tôi muốn phân tích. Đầu tiên, chúng tôi thêm các cột bổ sung vào df dataframe hiện có như sau:

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

Sau đó, chúng tôi chạy vòng lặp for trên vectơ chuỗi như bên dưới:

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
}

Các cột kết quả: chuỗiký tự sẽ chứa số lượng từ và ký tự và điều này sẽ đạt được chỉ trong một lần đối với một vectơ chuỗi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.