【问题标题】:Applying Custom Function to Data.Table将自定义函数应用于 Data.Table
【发布时间】:2019-08-02 17:30:09
【问题描述】:

我需要对 data.table 中的所有行应用自定义函数,其中包含列 freq(数字)、ngram(每个单词由 _ 分隔的文本)。我还提供了 3 个常量值 - input1gramCount、input2gramCount、input3gramCount,而不是在 data.table 中。

当我尝试这个时,我得到了警告

Warning message:
In if (MatchedLen == 4) { :
the condition has length > 1 and only the first element will be used

似乎在抱怨 4 没有矢量化,但我希望它是一个常数。欢迎任何指点...

# Stupid Backoff
StupidBackoffScore <- function(freq, ngram, input1gramCount, input2gramCount, input3gramCount) {
    matchedLen = str_count(ngram, "_") + 1
    if (matchedLen == 4) {
        score = freq / input3gramCount
    } else if (matchedLen == 3) {
        score = 0.4 * freq / input2gramCount
    } else {
        # must be matchedLen 2
        score = 0.4 * 0.4 * freq / input1gramCount
    }
    return(score)
    }

allGrams <- allGrams %>%
    mutate(stupidBOScore = StupidBackoffScore(frequency, ngram, input1gramCount, input2gramCount, input3gramCount))

【问题讨论】:

  • 它抱怨“如果”没有向量化,来自基础 R 的警告。如果值是常量,您可以使用 first(matchedLen) == 4 代替。 (dplyr 和 data.table 都有第一个函数)
  • 它是 4thats 的常数,不匹配Len
  • 好的。在这种情况下,您需要重写程序,考虑到“if”是针对单个条件(针对“控制流”而不是矢量化计算)。或者,也许可以考虑使用 purrr 或类似的方式逐行应用该函数(尽管这将非常低效)。

标签: r data.table tidyverse


【解决方案1】:

我会这样做:

setDT(dt)
dt[, matchedLen := str_count(ngram, "_") + 1 ]
dt[, score := ifelse(matchedLen == 4, freq / input3gramCount,
                     ifelse(matchedLen == 3, 0.4 * freq / input2gramCount,
                        0.4 * 0.4 * freq / input1gramCount)) ]

为了便于阅读,我将matchedLen 创建为单独的列。如果您不需要matchedLen,您可以在创建分数后将其删除。

【讨论】:

  • 感谢@Frank。我通过 Frank 的输入切换到 if else 解决了这个问题,然后找到了 case_when——诀窍是意识到我不能使用 if。 Map 的设计很好,因为它直接使用 data.frame。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 2014-02-12
  • 2019-11-05
  • 2023-04-09
  • 1970-01-01
相关资源
最近更新 更多