【发布时间】:2016-06-15 19:49:55
【问题描述】:
我正在尝试使用一些自定义的差异度量来计算仅由名义变量组成的数据集中的所有观测值之间的所有成对差异。
数据看起来像
set.seed(3424)
(mydata <- data.table(paste(sample(letters[1:5], 5, replace=T),
sample(LETTERS[1:5], 5, replace=T),
sep = ","),
paste(sample(LETTERS[1:5], 5, replace=T),
sample(LETTERS[1:5], 5, replace=T),
sep = ","),
paste(sample(letters[1:5], 5, replace=T),
sample(letters[1:5], 5, replace=T),
sep = ",")))
V1 V2 V3
1: a,A E,E b,b
2: e,D C,A d,d
3: d,B B,C d,d
4: c,B A,E b,d
5: a,B C,D d,a
library(data.table)
library(dplyr)
library(stringr)
metric <- function(pair){
intersection <- 0
union <- 0
for(i in 1:ncol(mydata)){
A <- pair[[1]][[i]]
B <- pair[[2]][[i]]
if(sum(is.na(A),is.na(B))==1)
union = union + 1
if(sum(is.na(A),is.na(B))==0){
intersection <- intersection + length(intersect(A,B))/length(union(A,B))
union = union + 1
}
}
1 - intersection/union
}
diss <- matrix(nrow = nrow(mydata), ncol = nrow(mydata))
for(i in 1:(nrow(mydata)-1)){
print(i) ## to check progress ##
for(j in (i+1):nrow(mydata)){
pair <- rbind(mydata[i], mydata[j])
diss[j, i] <- apply(pair, 1, function(x) strsplit(x, split=",")) %>% metric()
}
}
这些循环可以工作,但当 mydata 有 1000 多行和 100 多列时会非常慢。
我在这里使用的指标是 Jaccard 索引,但它是一个嵌套版本。由于数据中的每个元素都不是单个值。因此,我没有将每两个级别视为匹配(0)或不同(1),而是在比较级别时也使用 Jaccard。
更新:
关于我的数据的一些上下文,而不是我编造的玩具数据。
- 每一行代表一个查询,即“SELECT ... FROM ... WHERE ... ...”。
- 每一列都包含查询中的部分信息,即第一列包含“SELECT”和“FROM”之间的所有内容,第二列包含“FROM”和“WHERE”之间的内容,等等。
- 有 100 列和 400 行,但我不明白为什么会有这么多列。
-
一个单元格中的元素数量可以是任意的,一些单元格包含很长的值列表,而许多实际上是
NAs。例如。SELECT 1: NA 2:p1.PLAYERID,f1.PLAYERNAME,p2.PLAYERID,f2.PLAYERNAME 3: PLAYER f1,PLAYER f2,PLAYS p1 4: NA 5: NA 6: c1.table_name t1,c2.table_name t2 7: NA ... 400: asd,vrht,yuetr,wxeq,yiknuy,sce,ercher
【问题讨论】:
-
在某种程度上,速度慢可能是由于
metric()的编码方式。如果您解释其背后的基本原理/指标的作用(在问题的主体中,而不是在 cmets 中),它可能会让其他人更容易重新实现。 -
@Frank 谢谢。又忘记了。
-
创建 mydata 的第一行代码不会创建显示的输出。
-
@JacobH 通过这样做,我可以在
a,A和a,B之间分配一些相似性。 -
请在第一次调用
sample()之前用set.seed()定义一个固定的随机数生成种子值。这将使您的玩具数据可重现。然后,每个人都将使用相同的数据集,并可以比较结果。
标签: r performance loops