Преобразовать для l oop в (?) Применить в R - PullRequest
0 голосов
/ 17 января 2020

Мне нужна ваша помощь с этими двумя для циклов в R, потому что буквально часы тратятся на выполнение работы, и я уже попробовал несколько, чтобы выполнить работу сам ...:

for (i in 1:nrow(neg.sent.dictionary)){
    text <- gsub(neg.sent.dictionary$pattern[i], neg.sent.dictionary$replacement[i], text, fixed = 
    FALSE)
   }
for (i in 1:nrow(sent.dictionary)){
    neg.sent.dictionary$scored[i] <- ifelse(grepl(neg.sent.dictionary$feature[i], text, fixed = TRUE),
    TRUE, neg.sent.dictionary$scored[i])
   }

Вот как выглядит (отриц.) Sent.dictionary:
neg.sent.dictionary data
sent.dictionary data

А текст - это огромный символьный вектор.

Буду очень признателен, если кто-нибудь сможет мне помочь!

1 Ответ

0 голосов
/ 17 января 2020

Если вам нужно только обновить столбец оценки, я рекомендую использовать stringi::stri_detect_regex:

# stringi.regex
neg.sent.dictionary$scored <- 
    stringi::stri_detect_regex(text, neg.sent.dictionary$pattern) | neg.sent.dictionary$scored

Однако, если вам нужно изменить text и обновить оценку Вы можете изменить text с Внутренним gsub в пределах l oop, что немного быстрее. Но вынуждает вас проверять все аргументы вне функции:

# internal.gsub
p <- neg.sent.dictionary$pattern
r <- neg.sent.dictionary$replacement
for(i in 1:NROW(neg.sent.dictionary)) 
    text <- .Internal(gsub(p[i], r[i], text, F, F, F, F))

Я предлагаю все же для l oop, так как семейство * apply обычно одинаково эффективно, или медленнее по сравнению с for для l oop.

После изменения text вместо него можно использовать stringi::stri_detect_fixed, так как он может соответствовать намного быстрее по сравнению с версия регулярного выражения:

# stringi.fixed
neg.sent.dictionary$scored <- 
    stringi::stri_detect_fixed(text, neg.sent.dictionary$feature) | neg.sent.dictionary$scored

Я запустил несколько микробенчмарков, чтобы проверить производительность нескольких подходов. Я тестировал их в 4 различных сценариях ios:

  1. Маленький текст, Маленький словарь
  2. Большой текст, Маленький словарь
  3. Маленький текст, Большой словарь
  4. Большой текст, Большой словарь

Рекомендуемые решения называются stringi.regex, internal.gsub и stringi.fixed соответственно. Вот мои настройки:

library(tidyverse)

text <- "123 \"StackOverflow\""
neg.sent.dictionary <- tibble(
    pattern=c("\\d+",  "true|false|null",  "\"\\w+\""),
    replacement=c("number", "boolean", "string"),
    feature=c("number", "boolean", "string"),
    scored=F
)

# Small
bigger.text <- text
# Bigger 
bigger.text <- paste(rep(text, 1e4), collapse=" ")

# Small
bigger.nsd <- neg.sent.dictionary
# Bigger
bigger.nsd <- bind_rows(rep(list(neg.sent.dictionary), 1e3))


microbenchmark::microbenchmark(
    internal.gsub={
        p = bigger.nsd$pattern
        r = bigger.nsd$replacement
        for(i in 1:NROW(bigger.nsd)) 
            .Internal(gsub(p[i], r[i], bigger.text, F, F, F, F))
    },
    gsub={
        for (i in 1:nrow(bigger.nsd)){
            gsub(bigger.nsd$pattern[i], bigger.nsd$replacement[i], bigger.text, fixed = FALSE)
        }
    },
    unit="u"
)



p = bigger.nsd$pattern
r = bigger.nsd$replacement
for(i in 1:NROW(bigger.nsd)) 
    bigger.text.2 = .Internal(gsub(p[i], r[i], bigger.text, F, F, F, F))

microbenchmark::microbenchmark(
    stringi.regex={
        stringi::stri_detect_regex(bigger.text, bigger.nsd$pattern) | bigger.nsd$scored
    },
    stringi.fixed={
        stringi::stri_detect_fixed(bigger.text.2, bigger.nsd$feature) | bigger.nsd$scored
    },
    for.loop.internal.grepl={
        f = bigger.nsd$feature
        s = bigger.nsd$scored
        for (i in 1:nrow(bigger.nsd))
            .Internal(grepl(f[i], bigger.text.2, F, F, F, T, F, F)) | s[i]
    },
    for.loop.ifelse={
        for (i in 1:nrow(bigger.nsd)){
            ifelse(grepl(bigger.nsd$pattern[i], bigger.text.2, fixed = TRUE), TRUE, bigger.nsd$scored[i])
        }
    },
    unit="u"
)

А вот и результаты:

# 1. Small text, Small dictionary

Unit: microseconds
          expr    min      lq     mean  median      uq     max neval cld
 internal.gsub 2566.4 2711.10 3058.682 2823.70 3038.30 10098.0   100   a
          gsub 2703.3 2846.45 3331.547 2956.55 3288.55 18270.4   100   a


 Unit: microseconds
                    expr    min      lq     mean  median      uq     max neval cld
           stringi.regex   68.3   83.65  103.597  100.25  114.30   219.3   100  a 
           stringi.fixed    9.8   13.75   24.321   25.35   32.05    49.6   100  a 
 for.loop.internal.grepl 3029.7 3302.40 3721.852 3485.95 3803.45 10038.2   100   b
         for.loop.ifelse 3010.8 3317.50 3777.069 3547.45 3918.30  8917.9   100   b



# 2. Bigger text, Small dictionary

Unit: microseconds
          expr     min       lq     mean   median       uq     max neval cld
 internal.gsub 18934.6 20265.15 22315.87 20908.40 22121.30 70715.8   100   a
          gsub 19726.7 20593.55 22239.65 21181.75 21998.85 36940.8   100   a

 Unit: microseconds
                    expr    min      lq     mean  median      uq     max neval cld
           stringi.regex 1140.4 1222.35 1473.995 1268.40 1470.30  3142.4   100  b 
           stringi.fixed  193.5  209.40  271.207  225.75  257.20  2642.2   100 a  
 for.loop.internal.grepl 3825.5 4102.20 4997.894 4437.90 5316.70 11796.2   100   c
         for.loop.ifelse 4174.0 4419.95 5001.795 4662.15 5059.05  8682.3   100   c



# 3. Small text, Bigger dictionary

Unit: microseconds
          expr     min       lq     mean   median       uq     max neval cld
 internal.gsub 32073.3 33212.40 36108.31 34489.55 37420.65 57649.1   100  a 
          gsub 42647.7 44619.95 48733.21 46908.30 50926.50 67080.3   100   b

 Unit: microseconds
                    expr     min       lq      mean   median       uq     max neval  cld
           stringi.regex 53773.7 54816.20 57261.168 55394.05 57517.45 80971.4   100    d
           stringi.fixed   284.6   326.45   361.985   337.60   369.25   705.2   100 a   
 for.loop.internal.grepl  7792.3  8316.00  8881.116  8613.40  8957.30 16013.8   100  b 
         for.loop.ifelse 17276.4 18438.95 20272.754 19306.30 22309.25 34873.0   100   c  



# 4. Bigger text, Bigger dictionary

Unit: microseconds
          expr      min       lq     mean   median       uq      max neval cld
 internal.gsub 16483350 17148515 17897795 17713030 18624919 20713810   100   a
          gsub 16550789 17180693 18020193 17772800 18714014 21618478   100   a

 Unit: microseconds
                    expr       min        lq      mean    median        uq       max neval cld
           stringi.regex 1089151.1 1104097.2 1281581.9 1140744.2 1302083.6 2350601.5   100   c
           stringi.fixed  195208.3  198095.9  202585.5  201291.5  206144.1  230414.8   100 a  
 for.loop.internal.grepl  781006.4  791378.0  982425.3  817768.6  892169.8 2090793.6   100  b 
         for.loop.ifelse 1110029.5 1132167.4 1356409.4 1161535.1 1230636.3 3058030.2   100   c
...