문자열 열의 각 행에서 주어진 문자의 발생 횟수를 계산하는 방법은 무엇입니까?


103

특정 변수에 텍스트 문자열이 포함 된 data.frame이 있습니다. 각 개별 문자열에서 주어진 문자의 발생 횟수를 계산하고 싶습니다.

예:

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

문자열에서 "a"의 발생 횟수 (예 : c (2,1,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

stringr 패키지는 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
@DWin-사실이지만 stringsAsFactors = FALSE데이터 프레임을 정의 할 때 추가하여이 문제를 피했습니다 .
Dason

불분명해서 죄송합니다. 나는 실제로 Tim riffe에게 응답하고 그의 기능이 문제가있는 오류를 던졌다 고 말했습니다. 그는 문제의 재정의를 사용했을 수도 있지만 그렇게 말하지 않았습니다.
IRTFM

그래, 나도 stringsAsFactors=TRUE내 comp에서했다.하지만 이것에 대해서는 언급하지 않았다
tim 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
OK-아마 몇 번 과 함께 사용했을 때만 표현력 이 느껴지 겠지만, 그 콤보는 플러그가 필요하다고 생각할만큼 충분히 강력합니다. regmatchesgregexpr
Josh O'Brien

regmatches비교적 새로운 것입니다. 2.14에서 도입되었습니다.
Dason

나는 당신이 regmatches 비트가 필요하다고 생각하지 않습니다. gregexpr 함수는 x의 각 요소에 대해 일치하는 항목의 인덱스가있는 목록을 반환합니다.
savagent

@savagent-각 문자열의 일치 수를 계산하는 데 사용할 코드를 공유해 주시겠습니까?
Josh O'Brien

1
죄송합니다. -1을 잊어 버렸습니다. 각 행에 sapply (gregexpr ( "g", q.data $ string), length)가 하나 이상 일치하는 경우에만 작동합니다.
savagent 2014-08-26

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

nchar에 전달하기 전에 factor 변수를 문자로 강제 변환합니다. 정규식 함수는 내부적으로이를 수행하는 것으로 보입니다.

다음은 벤치 마크 결과입니다 (테스트 크기를 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있습니다 (예 : 계수하려는 문자가와 같은 정규식 어설 션으로 해석 될 수있는 경우 ). .
C8H10N4O2

7
sum(charToRaw("abc.d.aa") == charToRaw('.'))

좋은 선택입니다.


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

IMHO가 가장 쉽고 깨끗한 방법은 다음과 같습니다.

q.data$number.of.a <- lengths(gregexpr('a', q.data$string))

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

어떻게 된 거죠? 나를 위해, lengths(gregexpr('a', q.data$string))반환 2 1 1하지 않습니다 2 1 0.
Finn Årup Nielsen


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 : 함수 "function (x) {sum ( 'a'== strsplit (as.character (x), '') [[1]])}"열 2의 각 행에 적용됩니다. 이 함수는 열 2 (x)의 각 행 값을 취하고 문자로 변환 (예 : 인수 인 경우)하며 모든 문자에서 문자열 분할을 수행합니다 ( "strsplit (as.character (x), ' ')'). 결과적으로 우리는 열 2의 각 행에 대한 문자열 값의 각 문자를 가진 벡터를 갖게됩니다.

3 : 벡터의 각 벡터 값을 계수 할 원하는 문자와 비교합니다 (이 경우 "a"( " 'a'==")). 이 연산은 True 및 False 값 "c (True, False, True, ....)"의 벡터를 반환하며, 벡터의 값이 계산하려는 문자와 일치하면 True가됩니다.

4 : 문자 'a'가 행에 나타나는 총 시간은 벡터 "sum (....)"의 모든 'True'값의 합으로 계산됩니다.

5 : 그런 다음 "unlist"함수를 적용하여 "lapply"함수의 결과를 압축 해제하고 데이터 프레임의 새 열에 할당합니다 ( "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
당신의 대답은 그것이하는 일에 대한 설명으로 훨씬 더 좋을 것입니다. 특히 정확히 단순한 표현이 아니기 때문에 신규 사용자에게는 더욱 그렇습니다 .
Khaine775

귀하의 의견에 대해 @ Khaine775에게 감사 드리며 게시물에 대한 설명이 부족한 것에 대해 사과드립니다. 게시물을 편집하고 작동 방식에 대한 더 나은 설명을 위해 몇 가지 의견을 추가했습니다.
bacnqn

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

효율적인 것은 아니지만 내 목적을 해결하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.