Bir dizedeki tüm kelimelerin sayısını sayın


82

Bir dizedeki kelimelerin sayısını sayan bir işlev var mı? Örneğin:

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

7 sonucu döndürmek için.


@ Martin'in aşağıdaki cevabına dayanarak, belirli bir metin dizesindeki cümle başına düşen kelimelerin sayısını sayan bir counterwordpersentence . Birkaç cümle içeren uzun bir metin için, tüm sözcükleri sayacak ve cümle başına ortalama sözcük sayısını ve toplam sözcük sayısını çıkaracaktır.
Paul Rougieux

1
str_count (temp $ soru1, "") +1, her kelimenin boşlukla ayrıldığını biliyorsanız, kolay olacaktır. Kitaplık dizesi altındadır.
Vivek Srivastava

Yanıtlar:


24

strsplitVe sapplyişlevlerini kullanabilirsiniz

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

2
lengthsHer bir elementin uzunluğunu bulan, artık R tabanındaki biraz yeni fonksiyonu kullanabileceğiniz bir güncelleme :lengths(strsplot(str, " "))
Nick Tierney

bu çok iyi sorun şu ki, "kelime, kelime, kelime" gibi bir şeyiniz olduğunda, 1
Dimitrios Zacharatos

71

\\WSözcük olmayan karakterleri eşleştirmek için normal ifade sembolünü +, bir satırdaki bir veya daha fazlasını belirtmek için kullanarak gregexprve bir dizedeki tüm eşleşmeleri bulmak için kullanın. Kelimeler, kelime ayırıcılarının sayısı artı 1'dir.

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

Bir "kelime" tatmin etmiyor, bu başına veya karakter vektörü, sonunda boş dizeleri başarısız olur \\Ws' olmayan kelimenin kavramını (bir Normal ifadelerle, birlikte işe yarayabilir \\S+, [[:alpha:]]vb, ama orada her zaman olacak normal ifade yaklaşımı olan uç durumlar olabilir), vb. Muhtemelen strsplither kelime için bellek ayıran çözümlerden daha etkilidir . Normal ifadeler bölümünde açıklanmıştır ?regex.

Güncelleme Yorumlarda ve @Andri tarafından farklı bir yanıtta belirtildiği gibi, yaklaşım (sıfır) ve tek kelimelik dizelerle ve sonunda noktalama işaretiyle başarısız oluyor

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

Diğer yanıtların çoğu da bu veya benzer (örneğin, birden çok boşluk) durumlarda başarısız olur. Bence cevabımın orijinal cevaptaki 'tek kelime kavramı' konusundaki uyarısı noktalama işaretleriyle ilgili sorunları kapsıyor (çözüm: farklı bir normal ifade seçin, örneğin, [[:space:]]+), ancak sıfır ve tek kelimelik durumlar bir problem; @ Andri'nin çözümü sıfır ve bir kelimeyi ayırt edemiyor. Bu nedenle, birinin yapabileceği kelimeleri bulmak için 'olumlu'

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

Giden

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

Yine normal ifade, farklı 'kelime' kavramları için iyileştirilebilir.

gregexpr()Hafıza verimli olduğu için kullanımını seviyorum . Kullanan strsplit()(@ user813966 gibi, ancak sözcükleri sınırlandırmak için normal bir ifadeyle) ve orijinal sınırlayıcı sözcük kavramını kullanan alternatif bir

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

Bunun, oluşturulan her kelime için ve ara kelime listesi için yeni hafıza ayırması gerekir. Veriler 'büyük' ​​olduğunda bu nispeten pahalı olabilir, ancak muhtemelen çoğu amaç için etkili ve anlaşılabilirdir.


str1 <- c('s ss sss ss', "asdf asd hello this is your life!"); sapply(gregexpr("\\W+", str1), length) + 1döner 4ve 8. Birincisi doğru, ikincisi çok fazla. Sanırım noktalama işaretlerini sayıyor.
Francis Smart

Sanırım cümlenin sonundaki noktalama işaretlerini sayıyor. Normal ifadeye başlangıç ​​ve bitiş eşleşmelerini göz ardı etmesini söylemek isteyeceğinizden oldukça eminim (üzgünüm bunun bir faydası yok yoksa kendim düzeltirim)
Francis Smart

sapply(gregexpr("\\W+", "word"), length) + 12 döndürür
jaycode

Teşekkürler @ fsmart - Sanırım noktalama işaretiyle ilgili endişenin, orijinal yanıttaki 'sözcük olmayan kavramı' hakkındaki sorumluluk reddi beyanıyla kapsanması. Yanıtı güncelledim.
Martin Morgan

@Jaycode teşekkürler, 1 (veya sıfır) kelime girişinin sayılamaması bir sorundur. Orijinal cevabı güncelledim.
Martin Morgan

49

En basit yol şudur:

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

... boşluksuz karakterler üzerindeki tüm dizileri sayar ( \\S+).

Peki ya hangi tür kelimeleri saymak istediğimize ve hangisinin tüm vektörler üzerinde çalıştığına karar vermemizi sağlayan küçük bir fonksiyona ne dersiniz ?

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

Kullanmak str_countişlevini stringrçıkış sırası ile kütüphane \wtemsil eder:

herhangi bir 'kelime' karakteri (mevcut yerel ayarda harf, rakam veya alt çizgi: UTF-8 modunda yalnızca ASCII harfleri ve rakamları dikkate alınır)

Misal:

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

Test edebildiğim tüm diğer 9 cevaptan sadece ikisi (Vincent Zoonekynd ve petermeissner tarafından) şimdiye kadar burada sunulan tüm girdiler için çalıştı, ancak bunlar da gerekli stringr.

Ancak yalnızca bu çözüm, şimdiye kadar sunulan tüm girdiler artı "foo+bar+baz~spam+eggs"veya gibi girdilerle çalışır "Combien de mots sont dans cette phrase ?".

Kıyaslama:

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

Çıktı:

6 10 10  8  9  9  7  6  6 11

Bu yaklaşım mükemmel, ancak yine de karşılaştığım bir sorun, kesme işareti içeren sözcükleri iki kez saymasıdır (örneğin, "Ben" veya "John's"). Bunu ele almanın bir yolu var mı?
Thredolsen

2
@Thredolsen, kelime ayırıcı olarak ele alınması gereken kesme işareti olmayacağından eminseniz, bir karakter sınıfı kullanabilirsiniz '[\\w\']+'(test edemezsiniz , bu nedenle xkcd.com/1638 geçerli olabilir), aksi takdirde emin değilim regex, genel durumda başa
çıkacak

1
Bunun iyi bir varsayım olup olmadığından emin değilim, ancak kesme işaretinden sonra her zaman yalnızca bir veya iki harf varsa, o zaman '\\w+(\'\\w{1,2})?'iyi bir çözüm olabilir.
arekolek

Teşekkür ederim. Her iki yaklaşım da çoğunlukla işe yarar, ancak benim durumumda '[\\ w \'] + 'daha iyi görünüyor, çünkü bazı kelimeler kesme işaretinden sonra 2'den fazla karakter içeriyor (örneğin: saat). İlgili takip sorusu: İki nokta üst üste işaretinin doğrudan sayısal bir karakter tarafından takip edildiği durumları da hariç tutmanın bir yolu var mı (örneğin '10: 15'i iki yerine tek kelime olarak sayın)?
Thredolsen

2
Bu yorumda, düz regex sözdizimi kullanacağım, bu nedenle örneklerde fazladan bazı ters eğik çizgilere ihtiyaç duyulacak. Gibi kelimeleri kapsamak için o'clockve friggin'yapabilirsin \w+('\w*)?(Kesme işaretiyle başlayan kelimeler var mı bilmiyorum?). Ek olarak saatleri idare etmek için, onları benzer şekilde eşleştirmeye çalışabilir \d?\d:\d\d|\w+('\w*)?veya ihtiyaçlarınıza bağlı olarak daha da karmaşık bir şey yapabilirsiniz. Ancak bu, R ile ilgili gittikçe daha az ve bir kelimeyi nasıl tanımladığınızla ilgili, bu yüzden belki özel ihtiyaçlarınızı karşılamak için ayrı bir soru gönderebilirsiniz?
arekolek

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

gsub(' {2,}',' ',str1)Yapar Tüm kelimeleri bir boşluk olan iki ya da daha fazla boşluk her tekrarlarını değiştirerek, sadece bir boşluk ile ayrılır.

strsplit(str,' ')Her boşluktaki cümleyi böler ve bir liste halinde sonuç döndürür. Bu [[1]]listeden kelimelerin vektörünü alır. lengthKaç kelimeleri sayar.

> 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

Peki ya sekmeler, yeni satırlar veya bölünemez boşluklar?
bartektartanus

5 yıllık bir cevabı diriltmenin yolu! '' Yerine herhangi bir tür beyaz boşluk eklemek için '\ s' (R içinde '\\ s') kullanın.
mathematical.coffee

Cevabımla ilgili bir bildirim aldım ve biraz iyileştirmek için başkalarına baktım: D Kızmayın! :) PS. Matematik ve kahveyi de seviyorum!
bartektartanus

13

str_match_allKelimelerinizi tanımlayacak normal bir ifade ile kullanabilirsiniz . Aşağıdakiler ilk, son ve çoğaltılmış boşluklarla çalışır.

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

Bu işlevi stringipaketten deneyin

   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
@bartektartanusBu güzel bir işlevsellik!
John

5
Teşekkürler :) Bu paketteki diğer işlevleri kontrol edin! Eminim ilginç bir şeyler bulacaksınız :) Her yorum memnuniyetle karşılanır!
bartektartanus

7

Qdap kütüphanesinde wc fonksiyonunu kullanabilirsiniz :

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

6

" "Sözcük sayısını elde etmek için çift ​​boşlukları kaldırabilir ve dizedeki sayıları sayabilirsiniz. Stringr ve rm_white{ qdapRegex } kullanın

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


5

Ayrıca stringipaketten, basit işlevstri_count_words

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

4

Çözüm 7, tek bir kelime olması durumunda doğru sonucu vermez. Gregexpr sonucundaki öğeleri saymamalısınız (eşleşmeyen yerlerde -1'dir), ancak> 0 olan öğeleri saymalısınız.

Ergo:

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

str1Sözcük olmayan karakterlerle başlar veya biterse bu yine de sorunlara neden olacaktır . Bu bir sorunsa, bu sürüm yalnızca sözcükler arasındaki boşlukları arayacaktır:sapply(gregexpr("\\b\\W+\\b", str, perl=TRUE), function(x) sum(x>0) ) + 1
Adam Bradley

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

kelimeler arasında çift / üçlü boşluk bırakıldığında sorun olmaz

Diğer tüm yanıtlarda, sözcükler arasında birden fazla boşluk bulunan sorunlar vardır.


2

gerektirir (stringr)

Çok basit bir işlevi tanımlayın

str_words <- function(sentence) {

  str_count(sentence, " ") + 1

}

Kontrol

str_words(This is a sentence with six words)

1

Kullanım nchar

dizelerin vektörü çağrılırsa x

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

Boşluk sayısını bulun ve bir tane ekleyin


1

Aşağıdaki işlevi ve normal ifadeyi, özellikle tek ve çift tireler ile uğraşırken, ilkinin genellikle bir kelime sonu olarak sayılmaması gereken, örneğin iyi bilinen hi-fi; çift ​​tire ise, parantez içindeki açıklamalar gibi, beyaz boşlukla sınırlı olmayan bir noktalama ayırıcısıdır.

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 kullanışlı bir pakettir. Ancak bu örnekteki sözcükleri tire nedeniyle fazla sayar.

stringi::stri_count_words(txt) #11 words

0

ile stringr pakette, bir de döngü için aracılığıyla örneğin dizeleri bir vektör çapraz olabilir basit bir komut dosyası yazabilirsiniz.

Diyelimki

df $ metin

analiz etmek istediğimiz dizelerin bir vektörünü içerir. Öncelikle, mevcut dataframe df'ye aşağıdaki gibi ek sütunlar ekliyoruz:

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

Sonra aşağıdaki gibi dizelerin vektörü üzerinde bir for-döngü çalıştırıyoruz:

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
}

Ortaya çıkan sütunlar: dizeler ve karakter , sözcük ve karakter sayılarını içerecek ve bu, bir dizi vektörü için tek seferde başarılacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.