gpt4 book ai didi

r - 以编程方式指定数据表中函数内的列名

转载 作者:行者123 更新时间:2023-12-02 00:00:29 28 4
gpt4 key购买 nike

这继续自 this question我前几天问过的(我现在想我应该同时问这个)。

数据

token.dt 是由数据表组成的列表,每个数据表对应n-grams中的n,包括n-grams(即,n 个单词序列)及其分数。

> head(token.dt[[2]])
V1 V2 mi2
1: 0 0 6.494179
2: 0 001 13.249067
3: 0 002 13.249067
4: 0 005 13.249067
5: 0 025 13.249067
6: 0 039 13.249067

> head(token.dt[[5]])
V1 V2 V3 V4 V5 mi5
1: 0 0 1 0 1 10.353265
2: 0 001 in apart for 6.807743
3: 0 001 in thick and 5.190449
4: 0 002 on each side 11.688710
5: 0 005 m in f 9.940322
6: 0 025 in aluminum which 8.249075

任务

任务是选择满足以下条件的 n-gram(即 token.dt 中表的行)。仅当 n-gram 的分数高于 n-1 grams 和识别出的 n+1 grams 的分数时,算法才保留该 n-gram通过以下方式:

  • n-gram 的前 n-1 个单词匹配的 n-1 grams 和
  • 第一个 n 个单词与 n-gram 匹配的 n+1 个 gram。

例如,请考虑以下内容。

> for (i in 2:n) setkeyv(token.dt[[i]], paste0("V", 1:i))
> token.dt[[2]][J("0", "1")]
V1 V2 mi2
1: 0 1 7.135725

> token.dt[[3]][J("0", "1")]
V1 V2 V3 mi3
1: 0 1 0 9.803035
2: 0 1 2 6.809646
3: 0 1 f 6.142258
4: 0 1 m 7.315181
5: 0 1 milligram 13.517241
6: 0 1 mv 13.517241
7: 0 1 of 1.151899
8: 0 1 the 0.214648
9: 0 1 to 3.633922

> token.dt[[4]][J("0", "1")]
V1 V2 V3 V4 mi4
1: 0 1 0 1 10.507784
2: 0 1 2 3 11.541023
3: 0 1 f the 3.927859
4: 0 1 m neutral 13.621798
5: 0 1 milligram of 3.852570
6: 0 1 milligram per 10.638304
7: 0 1 mv m 11.260860
8: 0 1 of making 12.235372
9: 0 1 the number 9.707556
10: 0 1 to 0 12.669723
11: 0 1 to 5 11.158356

这里,三元组(三个词的序列)0 1 0 没有被保留,因为尽管共享前两个词的二元组 (0 1) 具有较低的score (9.803035 > 7.135725),前三个单词与三元组 (0 1 0 1) 匹配的 4-gram 的得分高于所关注的三元组 (10.507784 > 9.803035)。

trigram 0 1 milligram 被保留,因为它的分数高于共享前两个单词的 bigram (13.517241 > 7.135725) 和前三个单词与 trigram ( 13.517241 > 3.852570、13.517241 > 10.638304)。

上述任务是通过以下方式以非编程方式实现的。

> z <- token.dt[[4]][token.dt[[3]][token.dt[[2]], allow.cartesian = TRUE], list(k = all(mi3 > max(mi2, mi4)), mi3), allow.cartesian = TRUE][(k)]
> head(z)
V1 V2 V3 k mi3
1: 0 1 milligram TRUE 13.51724
2: 0 1 mv TRUE 13.51724
3: 0 15 g TRUE 12.24260
4: 0 2 gram TRUE 13.52079
5: 0 2 mrads TRUE 13.34449
6: 0 3 wt TRUE 13.28771

我想知道的是如何以编程方式执行上述操作,即不对列名称进行硬编码(例如 mi3、mi4 等)。

失败的尝试

简单地使用paste0函数创建字符串并添加with = FALSE的参数似乎不起作用。

> i <- 3
> z <- token.dt[[i + 1]][token.dt[[i]][token.dt[[i - 1]], allow.cartesian = TRUE], list(k = all(paste0("mi", i) > max(paste0("mi", i - 1), paste0("mi", i + 1))), paste0("mi", i)), with = FALSE, allow.cartesian = TRUE][(k)]
Error in abs(j) : non-numeric argument to mathematical function

当场尝试对上面的字符串求值,导致找不到列。将 envir = .SD 添加到下面的 eval 会导致与下面相同的错误。

> z <- token.dt[[i + 1]][token.dt[[i]][token.dt[[i - 1]], allow.cartesian = TRUE], list(k = all(eval(parse(text = paste0("mi", i))) > max(eval(parse(text = paste0("mi", i - 1))), eval(parse(text = paste0("mi", i + 1))))), eval(parse(text = paste0("mi", i)))), allow.cartesian = TRUE][(k)]
Error in eval(expr, envir, enclos) : object 'mi3' not found

目前唯一可行的方法是首先连接必要的数据表,然后按照上述相同的方法进行操作。

> for (j in 2:4) {
+ if (j == 2) {
+ all <- copy(token.dt[[j]])
+ } else {
+ all <- token.dt[[j]][all, allow.cartesian = TRUE]
+ }
+ }

> head(all)
V1 V2 V3 V4 mi4 mi3 mi2
1: 0 0 1 0 13.292479 9.766820 6.494179
2: 0 001 in apart 13.233742 5.624795 13.249067
3: 0 001 in thick 13.005608 5.624795 13.249067
4: 0 002 on each 10.416711 7.301489 13.249067
5: 0 005 m in 5.625874 11.205271 13.249067
6: 0 025 in aluminum 13.443647 5.624795 13.249067

> z <- all[1:1000 , list(k = all(eval(parse(text = paste0("mi", i)), envir = .SD) > max(eval(parse(text = paste0("mi", i - 1)), envir = .SD), eval(parse(text = paste0("mi", i + 1)), envir = .SD))), mi = eval(parse(text = paste0("mi", i)), envir = .SD)), by = c(paste0("V", 1:i))][(k)]
> z <- unique(z)
> head(z)
V1 V2 V3 k mi
1: 0 1 milligram TRUE 13.51724
2: 0 1 mv TRUE 13.51724
3: 0 15 g TRUE 12.24260
4: 0 2 gram TRUE 13.52079
5: 0 2 mrads TRUE 13.34449
6: 0 3 wt TRUE 13.28771

但是,这慢得令人无法接受。处理 970,696 行中的 1,000 行(以上)需要五秒多的时间。鉴于我在这里使用的语料库比我想要应用该算法的语料库小得多,我正在寻找加速该过程的方法。

可重现的例子

下面的模拟数据集应该可以说明这一点。

token.dt <- list()
types <- combn(LETTERS, 3, paste, collapse = "")
set.seed(1)
data <- data.table(matrix(sample(types, 4 * 1E6, replace = TRUE), ncol = 4))
setkey(data, V1, V2, V3, V4)
set.seed(1)
for (n in 2:4) {
token.dt[[n]] <- unique(cbind(data[ , 1:n, with = FALSE]))
token.dt[[n]][ , paste0("mi", n) := runif(nrow(token.dt[[n]])) * 10]
}

如有任何建议,我们将不胜感激。

最佳答案

为了使eval 方法起作用,您必须首先构建整个表达式,然后是eval。我在你的样本的简化版本上运行了这个(40 个值而不是 4e6):

i <- 3
x <- parse(
text=paste0(
"list(k = all(mi", i, " > max(mi", i - 1,
", mi", i + 1, ")), mi", i, ")"
) )
token.dt[[i + 1]][
token.dt[[i]][token.dt[[i - 1]], allow.cartesian = TRUE],
eval(x),
allow.cartesian = TRUE
][(k)]
# V1 V2 V3 k mi3
# 1: CIX BQV OWY TRUE 6.870228
# 2: GIU IJM HMO TRUE 7.698414
# 3: NQR FHN DOY TRUE 9.919061
# 4: PSX IPQ ACN TRUE 7.774452

如您所见,以编程方式引用列是有效的。使用您的完整数据集(4MM 值),这在我的系统上运行了大约 3 秒。

关于r - 以编程方式指定数据表中函数内的列名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21706355/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com