首页 > 解决方案 > 将自定义函数应用于 data.table 不起作用,即使该函数单独看起来还可以

问题描述

tl,dr:我的功能似乎有效,但后来我对其进行了应用,但它没有。是功能还是应用?

数据

我有一个数据表,其中包含已标记为字符向量的文本:

   id                   text
1:  1    c("sadness", "joy")
2:  2   c("anger", "scream")
3:  3 c("relief", "sadness")

我想使用包含单词和相关情感值的字典来用情感值注释我的标记化文本:

     words emotion1 emotion2
1: sadness        1        5
2:   anger        2        6
3:  relief        3        7

终极目标

我期待我的 search_function 输出类似于此的内容:

my_emotion_function(c("relief", "sadness"), lexicon_emotions)
   emotion1 emotion2
1:        2        6
my_emotion_function(c("relief", "meh"), lexicon_emotions)
   emotion1 emotion2
1:        3        7
my_emotion_function(c("meh", "ugh"), lexicon_emotions)
   emotion1 emotion2
1:       NA       NA

将此应用于令牌,我将添加新列并用结果填充它们。

  id               text     emotion1 emotion2
1:  1  c("sadness", "joy")         1        5
2:  2  c("anger", "scream")        2        6
3:  3  c("relief", "sadness")      2        6

半途而废的功能

该函数采用字符向量,对匹配单词的(键控)情感词典进行子集化,并计算每个情感维度的平均分数。

my_emotion_function <- function(characters, lexicon){
  return(lexicon[.(characters), lapply(.SD, mean, na.rm = TRUE), .SDcols = 2:3])
}

我不明白的

我感到困惑和无法理解的是为什么这个函数在一个字符向量上测试时似乎运行良好(上面的例子,只在一个向量上测试它,运行良好),但是当我想将它应用到数据时.table,它不起作用。
我不确定该函数是否在某个方面有误,或者我是否将其重叠到 data.table 中。我不知道为什么单个实例可以工作,但不能在 data.table 上重复

如果我执行上面的代码,在每个“文本”行中使用相同数量的标记,那么无论单词如何,我都会为每个单元格获得 NA。

   id                   text emotion1 emotion2
1:  1    c("sadness", "joy")      NaN      NaN
2:  2   c("anger", "scream")      NaN      NaN
3:  3 c("relief", "sadness")      NaN      NaN

如果您使用不相等数量的标记(例如第一行)对其进行测试,则每一行都包含第一行的值。

   id                   text emotion1 emotion2
1:  1                sadness        1        5
2:  2   c("anger", "scream")        1        5
3:  3 c("relief", "sadness")        1        5

我找不到为什么我要么只得到相同的结果,要么到处都是 NA 的原因。

完整的复制代码

library(data.table)
table_of_tokens <- data.table("id" = 1:3,
                              "text" = list(c("sadness", "joy"),
                                            c("anger", "scream"),
                                            c("relief", "sadness")))
table_of_tokens[, "text" := as.character(text)]
#convert to character vector to use key-subsetting in data.table

lexicon_emotions <-
  data.table(
    "words" = c("sadness", "anger", "relief"),
    "emotion1" = 1:3,
    "emotion2" = 5:7
  )
setkey(lexicon_emotions, words)

my_emotion_function <- function(characters, lexicon) {
  return(lexicon[.(characters), 
                 lapply(.SD, mean, na.rm = TRUE), .SDcols = 2:3])
}
table_of_tokens[, c("emotion1", "emotion2") := 
                  my_emotion_function(text, lexicon_emotions)]

信用:这基本上是对syuzhet R 包的重写,它依赖于 data.frames,因此在我的情况下对于大型数据集来说不够灵活或高效。

标签: rdata.tablesentiment-analysis

解决方案


编辑:这应该得到你想要的。

library(data.table)
table_of_tokens <- data.table(
    "id" = 1:3,
    "text" = list(
        c("sadness"), 
        c("anger", "scream"),
        c("relief", "grief"),
        c("relief", "grief", "sadness")
    )
)

lexicon_emotions <- data.table("words" = c("sadness", "anger", "relief"), 
                                                             "emotion1" = 1:3,
                                                             "emotion2" = 5:7,
                                                             key = "words")


emotions <- names(lexicon_emotions)[-1]
table_of_tokens[,
    (emotions) := {
        res <- lapply(text, function(x) {
            lexicon_emotions[words %chin% x,
                             lapply(.SD, mean, na.rm = TRUE),
                             .SDcols = emotions]
        })
        rbindlist(res)
    }
]

print(table_of_tokens)
> print(table_of_tokens)
   id                 text emotion1 emotion2
1:  1              sadness        1        5
2:  2         anger,scream        2        6
3:  3         relief,grief        3        7
4:  1 relief,grief,sadness        2        6

推荐阅读