तार के एक स्तंभ की प्रत्येक पंक्ति में किसी दिए गए चरित्र की घटना की संख्या की गणना कैसे करें?


103

मेरे पास एक डेटा.फ्रेम है जिसमें कुछ चर में एक पाठ स्ट्रिंग है। मैं प्रत्येक व्यक्तिगत स्ट्रिंग में किसी दिए गए चरित्र की घटनाओं की संख्या को गिनना चाहता हूं।

उदाहरण:

q.data<-data.frame(number=1:3, string=c("greatgreat", "magic", "not"))

मैं स्ट्रिंग (यानी। c। (2,1,0,0)) की संख्या की संख्या के साथ q.data के लिए एक नया कॉलम बनाना चाहता हूं।

केवल जटिल दृष्टिकोण जो मैंने प्रबंधित किया है, वह है:

string.counter<-function(strings, pattern){  
  counts<-NULL
  for(i in 1:length(strings)){
    counts[i]<-length(attr(gregexpr(pattern,strings[i])[[1]], "match.length")[attr(gregexpr(pattern,strings[i])[[1]], "match.length")>0])
  }
return(counts)
}

string.counter(strings=q.data$string, pattern="a")

 number     string number.of.a
1      1 greatgreat           2
2      2      magic           1
3      3        not           0

जवाबों:


141

स्ट्रिंग पैकेज वह str_countफ़ंक्शन प्रदान करता है जो ऐसा लगता है जो आप में रुचि रखते हैं

# Load your example data
q.data<-data.frame(number=1:3, string=c("greatgreat", "magic", "not"), stringsAsFactors = F)
library(stringr)

# Count the number of 'a's in each element of string
q.data$number.of.a <- str_count(q.data$string, "a")
q.data
#  number     string number.of.a
#1      1 greatgreat           2
#2      2      magic           1
#3      3        not           0

1
आपकी गति बहुत तेज थी, हालांकि इसे समस्या के साथ सफल होने के लिए मुख्य तर्क के आसपास as.character () की आवश्यकता है।
IRTFM

1
@ डब्लिन - यह सच है लेकिन मैंने stringsAsFactors = FALSEडेटा फ्रेम को परिभाषित करते समय जोड़कर उस मुद्दे को टाल दिया ।
दासन

क्षमा करें, मैं स्पष्ट नहीं था। मैं वास्तव में टिम रिफ़ का जवाब दे रहा था और उसे बता रहा था कि उसके कार्य ने समस्या उत्पन्न की है। उन्होंने समस्या के आपके पुनर्निर्धारण का उपयोग किया हो सकता है, लेकिन उन्होंने ऐसा नहीं कहा।
IRTFM

हाँ, मैंने भी किया था, stringsAsFactors=TRUEमेरे COMP पर, लेकिन इस का उल्लेख नहीं किया
टिम riffe

एक कारक में एक स्ट्रिंग के लिए खोज करना काम करेगा str_count (d $ factor_column, 'A') लेकिन इसके विपरीत नहीं
Nitro

65

यदि आप आधार R को नहीं छोड़ना चाहते हैं, तो यहां एक पर्याप्त रसीद और स्पष्ट संभावना है:

x <- q.data$string
lengths(regmatches(x, gregexpr("a", x)))
# [1] 2 1 0

2
ठीक है - हो सकता है कि आप केवल एक बार अभिव्यक्त होने का अनुभव करेंगे regmatchesऔर gregexprएक साथ कुछ बार इस्तेमाल करेंगे , लेकिन यह कॉम्बो इतना शक्तिशाली है कि मुझे लगा कि यह एक प्लग के योग्य है।
जोश ओ'ब्रायन

regmatchesअपेक्षाकृत नया है। इसे 2.14 में पेश किया गया था।
दासन

मुझे नहीं लगता कि आपको रिगमैच बिट की जरूरत है। फ़ंक्शन gregexpr x के प्रत्येक तत्व के लिए मिलान की गई आवृत्तियों के सूचकांकों के साथ एक सूची देता है।
प्रचंड

@savagent - क्या आप उस कोड को साझा करना चाहेंगे जिसे आप प्रत्येक स्ट्रिंग में मैचों की संख्या की गणना करने के लिए उपयोग करेंगे?
जोश ओ ब्रायन

1
क्षमा करें, मैं -1 के बारे में भूल गया। यह केवल तभी काम करता है जब प्रत्येक पंक्ति में कम से कम एक मैच हो, sapply (gregexpr ("g", q.data $ string), लंबाई)।
प्रचंड

18
nchar(as.character(q.data$string)) -nchar( gsub("a", "", q.data$string))
[1] 2 1 0

ध्यान दें कि मैं nchar को पारित करने से पहले, कारक चर को जोर देता हूं। रेगेक्स फ़ंक्शन आंतरिक रूप से ऐसा करते दिखाई देते हैं।

यहां बेंचमार्क परिणाम (परीक्षण के आकार को 3000 पंक्तियों तक बढ़ाया गया है)

 q.data<-q.data[rep(1:NROW(q.data), 1000),]
 str(q.data)
'data.frame':   3000 obs. of  3 variables:
 $ number     : int  1 2 3 1 2 3 1 2 3 1 ...
 $ string     : Factor w/ 3 levels "greatgreat","magic",..: 1 2 3 1 2 3 1 2 3 1 ...
 $ number.of.a: int  2 1 0 2 1 0 2 1 0 2 ...

 benchmark( Dason = { q.data$number.of.a <- str_count(as.character(q.data$string), "a") },
 Tim = {resT <- sapply(as.character(q.data$string), function(x, letter = "a"){
                            sum(unlist(strsplit(x, split = "")) == letter) }) }, 

 DWin = {resW <- nchar(as.character(q.data$string)) -nchar( gsub("a", "", q.data$string))},
 Josh = {x <- sapply(regmatches(q.data$string, gregexpr("g",q.data$string )), length)}, replications=100)
#-----------------------
   test replications elapsed  relative user.self sys.self user.child sys.child
1 Dason          100   4.173  9.959427     2.985    1.204          0         0
3  DWin          100   0.419  1.000000     0.417    0.003          0         0
4  Josh          100  18.635 44.474940    17.883    0.827          0         0
2   Tim          100   3.705  8.842482     3.646    0.072          0         0

3
यह उत्तरों में सबसे तेज़ समाधान है, लेकिन वैकल्पिक fixed=TRUEको पास करके अपने बेंचमार्क पर ~ 30% तेज़ी से बनाया जाता है gsub। कुछ मामलों में कर रहे हैं fixed=TRUEकी जाएगी आवश्यक (यानी, जब चरित्र आप की गणना करना चाहते जैसे एक regex दावे के रूप में व्याख्या की जा सकती .)।
C8H10N4O2


5

stringiपैकेज कार्य प्रदान करता stri_countहै और stri_count_fixedजो बहुत तेजी से कर रहे हैं।

stringi::stri_count(q.data$string, fixed = "a")
# [1] 2 1 0

बेंचमार्क

@ 42- के जवाब से सबसे तेज दृष्टिकोण की तुलना में और 30.000 तत्वों के साथ एक वेक्टर के लिए पैकेज से बराबर फ़ंक्शन केstringr लिए।

library(microbenchmark)

benchmark <- microbenchmark(
  stringi = stringi::stri_count(test.data$string, fixed = "a"),
  baseR = nchar(test.data$string) - nchar(gsub("a", "", test.data$string, fixed = TRUE)),
  stringr = str_count(test.data$string, "a")
)

autoplot(benchmark)

डेटा

q.data <- data.frame(number=1:3, string=c("greatgreat", "magic", "not"), stringsAsFactors = FALSE)
test.data <- q.data[rep(1:NROW(q.data), 10000),]

यहां छवि विवरण दर्ज करें



2

मुझे यकीन है कि कोई बेहतर कर सकता है, लेकिन यह काम करता है:

sapply(as.character(q.data$string), function(x, letter = "a"){
  sum(unlist(strsplit(x, split = "")) == letter)
})
greatgreat      magic        not 
     2          1          0 

या एक समारोह में:

countLetter <- function(charvec, letter){
  sapply(charvec, function(x, letter){
    sum(unlist(strsplit(x, split = "")) == letter)
  }, letter = letter)
}
countLetter(as.character(q.data$string),"a")

मैं पहले एक के साथ एक त्रुटि पाने के लिए लगता है ... और दूसरा एक ... (इन सभी को बेंचमार्क करने की कोशिश कर रहा था।)
IRTFM

1

आप बस स्ट्रिंग डिवीजन का उपयोग कर सकते हैं

require(roperators)
my_strings <- c('apple', banana', 'pear', 'melon')
my_strings %s/% 'a'

जो आपको 1, 3, 1, 0. देगा। आप नियमित अभिव्यक्ति और पूरे शब्दों के साथ स्ट्रिंग विभाजन का भी उपयोग कर सकते हैं।



0

नीचे दिए गए प्रश्न को यहां स्थानांतरित कर दिया गया है, लेकिन ऐसा लगता है कि यह पृष्ठ सीधे फराह एल के प्रश्न का उत्तर नहीं देता है। आर में 101 में 1 नंबर कैसे खोजें

तो, मैं यहां एक उत्तर लिखूंगा, बस मामले में।

library(magrittr)
n %>% # n is a number you'd like to inspect
  as.character() %>%
  str_count(pattern = "1")

https://stackoverflow.com/users/8931457/farah-el


0

फिर भी एक और base Rविकल्प हो सकता है:

lengths(lapply(q.data$string, grepRaw, pattern = "a", all = TRUE, fixed = TRUE))

[1] 2 1 0

-1

अगली अभिव्यक्ति काम करती है और केवल अक्षरों का ही नहीं, प्रतीकों का भी काम करती है।

अभिव्यक्ति निम्नानुसार काम करती है:

1: यह डेटाफ़्रेम q.data के कॉलम पर lapply का उपयोग कॉलम 2 की पंक्तियों पर पुनरावृति करने के लिए करता है ("lapply (q.data [, 2],"),)

2: यह कॉलम 2 की प्रत्येक पंक्ति पर एक फंक्शन "फ़ंक्शन (x) {sum ('a' == strsplit (as.character (x), '') [[1]]}" पर लागू होता है। फ़ंक्शन कॉलम 2 (x) के प्रत्येक पंक्ति मान को लेता है, चरित्र में कनवर्ट करता है (उदाहरण के लिए यह एक कारक है), और यह प्रत्येक वर्ण पर स्ट्रिंग का विभाजन करता है ("strsplit (as.character (x), ') ') ")। परिणामस्वरूप, हमारे पास स्तंभ 2 के प्रत्येक पंक्ति के स्ट्रिंग मान के प्रत्येक वर्ण के साथ एक वेक्टर है।

3: वेक्टर के प्रत्येक वेक्टर मान की गणना वांछित चरित्र के साथ की जाती है, इस मामले में "a" ("'a' ==")। यह ऑपरेशन ट्रू और फाल्स वैल्यूज के एक वेक्टर को लौटाएगा "c (ट्रू, फल्स, ट्रू, ....)", ट्रू होने पर वेक्टर के वैल्यू को गिने जाने वाले वांछित कैरेक्टर से मैच करता है।

4: पंक्ति में दिखाई देने वाला कुल वर्ण 'a' वेक्टर "sum (....)" के सभी 'ट्रू' मानों के योग के रूप में आंका जाता है।

5: फिर इसे "लेप्ली" फ़ंक्शन के परिणाम को अनपैक करने के लिए "अनलिस्ट" फ़ंक्शन को लागू किया जाता है और इसे डेटाफ़्रेम ("q.data $ number.of.a <-unlist (...) में एक नए कॉलम में असाइन किया जाता है। ")

q.data$number.of.a<-unlist(lapply(q.data[,2],function(x){sum('a' == strsplit(as.character(x), '')[[1]])}))

>q.data

#  number     string     number.of.a
#1   greatgreat         2
#2      magic           1
#3      not             0

1
आपका जवाब बहुत बेहतर होगा कि यह क्या करता है, खासकर नए उपयोगकर्ताओं के लिए, यह बिल्कुल सरल अभिव्यक्ति नहीं है ।
खैने 775

धन्यवाद @ Khaine775 आपकी टिप्पणी और पोस्ट के विवरण की कमी के लिए मेरी माफी के लिए। मैंने पोस्ट को संपादित किया है और यह कैसे काम करता है के बेहतर विवरण के लिए कुछ टिप्पणियां जोड़ीं।
बेकन

-2
s <- "aababacababaaathhhhhslsls jsjsjjsaa ghhaalll"
p <- "a"
s2 <- gsub(p,"",s)
numOcc <- nchar(s) - nchar(s2)

कुशल नहीं हो सकता लेकिन मेरे उद्देश्य को हल करो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.