krl*_*mlr 2 algorithm r distance
test我正在寻找一种实现,可以确定一个(例如, )数据帧中的所有记录与第二个(例如,)数据帧中的任何记录的高尔距离的最小值training。结果是一个向量,其中 的每一行都有一个元素test。
数据是具有无序分类属性的分类数据,并且可以如下生成:
set.seed(20130926L)
DIMS <- 12
CATS <- 2
create.data <- function(SPARSITY) {
sparse.data <- rbinom(CATS ** DIMS, 1, SPARSITY)
sparse.array <- array(sparse.data, dim=rep(CATS, DIMS))
sparse.table <- as.table(sparse.array)
sparse.df <- as.data.frame(sparse.table)
sparse.df <- subset(sparse.df, Freq > 0, select=-Freq)
sparse.df
}
data.train <- create.data(0.001)
data.test <- create.data(0.01)
head(data.train, 3)
## Var1 Var2 Var3 Var4 Var5 Var6 Var7 Var8 Var9 Var10 Var11 Var12
## 745 A A A B A B B B A B A A
## 1156 B B A A A A A B A A B A
## 1574 B A B A A B A A A B B A
summary(data.test)
## Var1 Var2 Var3 Var4 Var5 Var6 Var7 Var8 Var9 Var10
## A:24 A:31 A:23 A:20 A:30 A:27 A:22 A:20 A:26 A:23
## B:24 B:17 B:25 B:28 B:18 B:21 B:26 B:28 B:22 B:25
## Var11 Var12
## A:24 A:22
## B:24 B:26
Run Code Online (Sandbox Code Playgroud)
对于 中的所有行,如何找到高尔距离最小的data.test行data.training(或至少是到该特定行的距离)?下面的代码可以工作,但是对于 20 个属性或超过 2 个类别来说已经需要太多内存:
nrow(data.test)
## [1] 48
library(StatMatch, quietly=T, warn.conflicts=F)
apply(gower.dist(data.train, data.test), 2, min)
## [1] 0.3333 0.4167 0.2500 0.5000 0.3333 0.4167 0.2500 0.3333 0.2500 0.4167
## [11] 0.5000 0.3333 0.3333 0.3333 0.4167 0.4167 0.2500 0.4167 0.1667 0.3333
## [21] 0.4167 0.3333 0.4167 0.5000 0.3333 0.5000 0.5000 0.4167 0.3333 0.3333
## [31] 0.2500 0.4167 0.5000 0.4167 0.3333 0.5000 0.3333 0.4167 0.3333 0.3333
## [41] 0.5000 0.5833 0.5000 0.2500 0.3333 0.4167 0.3333 0.5000
Run Code Online (Sandbox Code Playgroud)
该函数cluster::daisy()还返回距离矩阵。
类似:如何计算大型数据帧的欧几里德距离(并仅保存摘要)。在那里,建议对 的子集多次调用距离函数data.train。我可以做到这一点,但计算时间仍然令人望而却步。
毕竟,高尔距离的定义允许更有效的算法,也许是一种递归分而治之的方法,逐个属性地操作并在子集上调用自身。回想一下,高尔距离是属性距离的(加权)总和,其定义为
下面是一个简单的演示,其中计算和(A, A)
的所有组合之间的高尔距离。在一个属性上不同的行的距离为 0.5,在两个属性上不同的行的最大距离为 1.0:AB
(ex.train <- expand.grid(Var1=LETTERS[1:2], Var2=LETTERS[1:2]))
## Var1 Var2
## 1 A A
## 2 B A
## 3 A B
## 4 B B
ex.test <- ex.train[1, ]
gower.dist(ex.train, ex.test)
## [,1]
## [1,] 0.0
## [2,] 0.5
## [3,] 0.5
## [4,] 1.0
Run Code Online (Sandbox Code Playgroud)
如果按列分析train.data和test.data,则可能的实现可能如下所示:
v第一列的
所有值级别test.data第一列有价值的子集vtrain.data第一列有价值的子集vtrain.data第一列有价值的子集<> v是否真的没有实现,或者可能有一篇描述这种算法的论文?
我不熟悉高尔距离,但从您的描述来看,对于无序分类属性,高尔距离等于汉明距离除以向量的长度。换句话说,向量x和之间的高尔距离y就是mean(x!=y)。在这种情况下,您可以通过避免计算整个距离矩阵而是使用 来节省大量计算时间colSums。下面是一个示例,包含三个级别和 10000 个训练行:
> set.seed(123)
> train.rows<-10000
> test.rows<-100
> cols<-20
> levels<-c("a","b","c")
> train.set<-sample(levels,train.rows*cols,T)
> dim(train.set)<-c(train.rows,cols)
> test.set<-sample(levels,test.rows*cols,T)
> dim(test.set)<-c(test.rows,cols)
> system.time(gdist<-apply(gower.dist(train.set,test.set),2,min))
user system elapsed
13.396 0.324 13.745
> system.time(hdist<-apply(test.set,1,function(x) min(colSums(x!=t(train.set))/cols)))
user system elapsed
0.492 0.008 0.504
> identical(hdist,gdist)
[1] TRUE
Run Code Online (Sandbox Code Playgroud)
如果数据不是离散且无序的,那么高尔距离的公式是不同的,但我怀疑有一种类似的方法可以更有效地计算它,而无需通过 计算整个距离矩阵gower.dist。
t(train.set)更新:通过使用@Frank的建议,并预先生成而不是在函数内生成,可以提高效率:
require(microbenchmark)
ttrain.set<-t(train.set)
microbenchmark(
a=apply(test.set,1,function(x) min(colSums(x!=t(train.set))/cols)),
b=apply(test.set,1,function(x) min(colSums(x!=ttrain.set)/cols)))
## Unit: milliseconds
## expr min lq median uq max neval
## a 523.3781 533.2950 589.0048 620.4411 725.0183 100
## b 367.5428 371.6004 396.7590 408.9804 496.4001 100
Run Code Online (Sandbox Code Playgroud)