2012-01-02 3 views
6

텍스트 데이터 (R)가 있고 일부 문자를 데이터 프레임의 다른 문자로 바꾸려고합니다. 나는 이것이 공간에서 strsplit을 사용하는 쉬운 작업이 될 것이라고 생각했다. 그런 다음 일치 시켜서 (% in %) 다음에 다시 붙일 수있는 벡터를 만들 수있다. 그런데 구두점을 생각했습니다. 문장의 마지막 단어와 끝에 문장 부호 사이에는 공백이 없습니다.조건부 gsub 바꾸기

나는 복잡한 코드가 내 코드가되기보다는 내가 원하는 것을 얻을 수있는보다 쉬운 방법이 있다고 생각한다. 나는이 문제에 대한 방향을 고맙게 생각한다.

#Character String 
x <- "I like 346 ice cream cones. They're 99 percent good! I ate 46." 

#Replacement Values Dataframe 
    symbol text      
1 "346" "three hundred forty six" 
2 "99" "ninety nine"    
3 "46" "forty six" 

#replacement dataframe 
numDF <- 
data.frame(symbol = c("346","99", "46"), 
      text = c("three hundred forty six", "ninety nine","forty six"), 
      stringsAsFactors = FALSE) 

원하는 결과 :

[1] "I like three hundred forty six ice cream cones. They're ninety nine percent good! You ate forty six?") 

편집 : 비록 그 무엇을 나에게 보인다 것은 반군 GSUB가 없기 때문에 원래는이 조건 GSUB을받을.

+1

직접 numbers2words 기능을 사용하는 완벽한 솔루션은 ...입니다. 방금 게시물을 편집했습니다. 희망을 품지 마라 :) –

+0

그 조쉬에 대해 유감스럽게 생각한다. 그것을 돌보고 귀하의 회신에 감사드립니다. 나는 gsubfn 패키지에 대해 몰랐다. 지적 해 주셔서 감사합니다. –

답변

8

아마이, 조쉬 오브라이언의 대답에 의해 영감을 수행합니다

x <- "I like 346 ice cream cones. They're 99 percent good! I ate 46." 
numDF <- structure(c("346", "99", "46", "three hundred forty six", "ninety nine", 
"forty six"), .Dim = c(3L, 2L), .Dimnames = list(c("1", "2", 
"3"), c("symbol", "text"))) 

pat <- paste(numDF[,"symbol"], collapse="|") 
repeat { 
    m <- regexpr(pat, x) 
    if(m==-1) break 
    sym <- regmatches(x,m) 
    regmatches(x,m) <- numDF[match(sym, numDF[,"symbol"]), "text"] 
} 
x 
+0

Beautiful 아름다운 세 가지 답변을 모두 사용할 수 있지만 근력을 유지하면서 가장 똑바로 전진합니다. 고맙습니다. –

+0

+1 -'regmatches'에 대한 좋은 사용법을 보니 매우 좋습니다. –

6

이 솔루션은 같은 이름의 패키지에 gsubfn를 사용

library(gsubfn) 

(pat <- paste(numDF$symbol, collapse="|")) 
# [1] "346|99|46" 

gsubfn(pattern = pat, 
     replacement = function(x) { 
      numDF$text[match(x, numDF$symbol)] 
     }, 
     x) 
[1] "I like three hundred forty six ice cream cones. They're ninety nine percent good! I ate forty six." 
+0

Josh 나는 그것을 좋아하고 이것을 지정하지 않았지만 이것은 패키지를위한 것이며 기본 기능을 제외한 다른 것에 의존하지 않으려 고합니다. +1 –

4

당신은 공백 또는 워드 경계에 분할 할 수 있습니다 (이 단어와 문장 사이의 일치) :

> x 
[1] "I like 346 ice cream cones. They're 99 percent good! I ate 46." 
> strsplit(x, split='\\s|\\>|\\<') 
[[1]] 
[1] "I"  "like" "346"  "ice"  "cream" "cones" "."  
[8] ""  "They" "'re"  "99"  "percent" "good" "!"  
[15] ""  "I"  "ate"  "46"  "."  

그런 다음 교체 작업을 수행 할 수 있습니다.

+0

나는 당신의 대답으로 작동하게 만들었지 만 Karsten W.의 대답은 조금 더 순결하고 빠릅니다. 도와 주셔서 감사합니다. +1 –

+0

나는 이것을 좋아하지만, 일부 문자열 사이에 공백을 넣고 처리 된 결과를 다시 붙이기는 까다로울 것 같다. 그리고 단어와 문장 끝 문장 부호 사이에 *가 *있는 경우에는 분명히 그것을 잃을 것입니다 :'x <- "단어."; strsplit (x, split = '\\ s | \\> | \\ <') [[1]]'. –

+0

@Josh O'Brien 그것은 조슈 오브라이언 (goshub)을 사용하여 다음 구두점 ('?.!)과 선도적 인 공간을 찾고 구두점을 빼고 공간을 빼서 내게 도움이되었습니다. 이것은 4 줄의 코드를 더 필요로했다. (나는 더 빠른 길을 가졌다 고 확신한다.) 실제로 작동한다. –

2

당신이 정말로 자신의 알파 등가물에 숫자를 변환하고 싶었 여부를 정확히 밝혀지지 않았다. 그렇다면 훨씬 일반적인 전략이 여기에 있습니다. rhelp 아카이브에는 두 가지 숫자 - 텍스트 변환 함수가 있습니다 (Jim Lemon의 digits2text 및 John Fox의 numberstowords). 상자 밖으로 일

절단 및 Lemon's function from the HTML found here를 붙여 : 나는 또한 벡터화 된 접근 방식에 도착 gregexpr로 전환 일부 누락 된 줄 바꿈이 있었기 때문에

>  m <- gregexpr("[0-9]+", x) 
>  sym <- regmatches(x,m) 
>  regmatches(x,m) <- digits2text(as.numeric(sym[[1]])) 
illion = 0 
digilen = 3 
digitext = three hundred forty six 
[1] 6 4 3 
> 
> x 
[1] "I like three hundred forty six ice cream cones. They're three hundred forty six percent good! I ate three hundred forty six." 

내가 numberstowords의 일부를 편집 할 필요가 구문 분석을 엉망 (나는이 데모 아래의 성공적인 버전을 포함한다 : http://tolstoy.newcastle.edu.au/R/help/05/04/2715.html

,369 :에서 편집

>  m <- gregexpr("[0-9]+", x) 
>  sym <- regmatches(x,m) 
>  regmatches(x,m) <- numbers2words(as.numeric(sym[[1]])) 
> 
> x 
[1] "I like three hundred forty six ice cream cones. They're three hundred forty six percent good! I ate three hundred forty six." 

폭스의 기능을

numbers2words <- function(x){ 

    helper <- function(x){ 

     digits <- rev(strsplit(as.character(x), "")[[1]]) 
     nDigits <- length(digits) 
     if (nDigits == 1) as.vector(ones[digits]) 
     else if (nDigits == 2) 
      if (x <= 19) as.vector(teens[digits[1]]) 
       else trim(paste(tens[digits[2]], 
          Recall(as.numeric(digits[1])))) 
     else if (nDigits == 3) trim(paste(ones[digits[3]], "hundred", 
      Recall(makeNumber(digits[2:1])))) 
     else { 
      nSuffix <- ((nDigits + 2) %/% 3) - 1 
      if (nSuffix > length(suffixes)) stop(paste(x, "is too large!")) 
      trim(paste(Recall(makeNumber(digits[ 
       nDigits:(3*nSuffix + 1)])), 
       suffixes[nSuffix], 
       Recall(makeNumber(digits[(3*nSuffix):1])))) 
      } 
     } 
    trim <- function(text){ 
     gsub("^\ ", "", gsub("\ *$", "", text)) 
     }  


    makeNumber <- function(...) as.numeric(paste(..., collapse="")) 
    opts <- options(scipen=100) 
    on.exit(options(opts)) 
    ones <- c("", "one", "two", "three", "four", "five", "six", "seven", 

     "eight", "nine") 
    names(ones) <- 0:9 
    teens <- c("ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", 

     "sixteen", " seventeen", "eighteen", "nineteen") 
    names(teens) <- 0:9 
    tens <- c("twenty", "thirty", "forty", "fifty", "sixty", 
       "seventy", "eighty", "ninety") 
    names(tens) <- 2:9 
    x <- round(x) 
    suffixes <- c("thousand", "million", "billion", "trillion") 
    if (length(x) > 1) return(sapply(x, helper)) 
    helper(x) 
    } 
+0

DW 당신은 ​​내가 텍스트를 가져 와서 텍스트의 숫자를 줄이려고했다는 점에서 맞습니다. 나는 원래이 질문을 talkstats.com http://www.talkstats.com/showthread.php/22564-Replacement-in-gsub-as-a-function-argument에 게시했고 폭스 기능을 발견했다. 나는 거기 bryangoodrich에서 도움을 얻었지만 원래의 텍스트로 텍스트를 대체하는 숫자를 하위로 옮기는 과정에서 난관에 처했습니다. 이 질문은 퍼즐 조각을 다루는 데보다 구체적이었습니다. 도와 주셔서 감사합니다. + 1 –

+0

숫자 값을 talkstats에 게시 한 해당 단어로 대체하는 것에 대한 제 질문에 더 구체적으로 저에게 구체적으로 대답했습니다. 조건부 gsubbing에 대한 질문은 숫자 값을 다루는 사람들뿐만 아니라 많은 사람들에게 훨씬 더 일반화되어 있습니다. 내가 컴파일해야하는 약어 대체 기능에서 비슷한 접근법을 사용할 수 있습니다. –

+0

대체물이 숫자 값을 제대로 순환하지 못하는 것으로 나타났습니다. –

3

에서 Reduce을 사용하는 다른 솔루션.

list_df <- apply(numDF, 1, as.list) 
Reduce(function(x, l) gsub(l$symbol, l$text, x), list_df, init = x) 

EDIT. 여기에 귀하의`dput`'ed data.frame가 data.frame로 평가하지 않았다

list_df <- as.numeric(regmatches(x, gregexpr('[0-9]+', x))[[1]]) 
Reduce(function(x, l) gsub(l, numbers2words(l), x), list_df, init = x)