R类间距离矩阵
R Interclass distance matrix
这个问题是 how to extract intragroup and intergroup distances from a distance matrix? in R 的后续问题。在那个问题中,他们首先计算所有点的距离矩阵,然后简单地提取 inter-class 距离矩阵。我有一种情况,我想绕过初始计算并直接跳到提取,即我想直接计算 inter-class 距离矩阵。从链接示例中提取,通过调整,假设我在名为 df
:
的数据框中有一些数据
values<-c(0.002,0.3,0.4,0.005,0.6,0.2,0.001,0.002,0.3,0.01)
class<-c("A","A","A","B","B","B","B","A","B","A")
df<-data.frame(values, class)
我想要的是距离矩阵:
1 2 3 8 10
4 .003 .295 .395 .003 .005
5 .598 .300 .200 .598 .590
6 .198 .100 .200 .198 .190
7 .001 .299 .399 .001 .009
9 .298 .000 .100 .298 .290
R 中是否已经存在一种优雅而快速的方法来做到这一点?
编辑 在收到上述一维案例的良好解决方案后,我想到了一个额外的问题:高维案例呢,如果改为 df
看起来像这样:
values1<-c(0.002,0.3,0.4,0.005,0.6,0.2,0.001,0.002,0.3,0.01)
values2<-c(0.001,0.1,0.1,0.001,0.1,0.1,0.001,0.001,0.1,0.01)
class<-c("A","A","A","B","B","B","B","A","B","A")
df<-data.frame(values1, values2, class)
我有兴趣再次获得 class B
中的点与 class A
.[=18= 中的点之间的欧氏距离矩阵]
这里尝试生成每个组合,然后简单地从每个值中取差:
abs(matrix(Reduce(`-`, expand.grid(split(df$values, df$class))), nrow=5, byrow=TRUE))
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0.003 0.295 0.395 0.003 0.005
#[2,] 0.598 0.300 0.200 0.598 0.590
#[3,] 0.198 0.100 0.200 0.198 0.190
#[4,] 0.001 0.299 0.399 0.001 0.009
#[5,] 0.298 0.000 0.100 0.298 0.290
对于一般的 n
维欧氏距离,我们可以利用方程(不是 R,而是代数):
square_dist(b,a) = sum_i(b[i]*b[i]) + sum_i(a[i]*a[i]) - 2*inner_prod(b,a)
其中总和超过向量 a
和 b
的维度,对于 i=[1,n]
。这里,a
和 b
是 A
和 B
中的一对。这里的关键是,这个方程可以写成 A
和 B
.
中所有对的矩阵方程
在代码中:
## First split the data with respect to the class
n <- 2 ## the number of dimensions, for this example is 2
tmp <- split(df[,1:n], df$class)
d <- sqrt(matrix(rowSums(expand.grid(rowSums(tmp$B*tmp$B),rowSums(tmp$A*tmp$A))),
nrow=nrow(tmp$B)) -
2. * as.matrix(tmp$B) %*% t(as.matrix(tmp$A)))
备注:
- 内部
rowSums
为 B
中的每个 b
和 A
中的每个 a
计算 sum_i(b[i]*b[i])
和 sum_i(a[i]*a[i])
,分别
expand.grid
然后生成 B
和 A
之间的所有对。
- 外部
rowSums
计算所有这些对的 sum_i(b[i]*b[i]) + sum_i(a[i]*a[i])
。
- 然后将此结果重塑为
matrix
。注意这个矩阵的行数就是你要求的classB
的点数
- 然后减去所有对的内积的两倍。这个内积可以写成矩阵乘法
tmp$B %*% t(tmp$A)
,为了清楚起见,我省略了对矩阵的强制转换。
- 最后,取平方根。
将此代码与您的数据一起使用:
print(d)
## 1 2 3 8 10
##4 0.0030000 0.3111688 0.4072174 0.0030000 0.01029563
##5 0.6061394 0.3000000 0.2000000 0.6061394 0.59682493
##6 0.2213707 0.1000000 0.2000000 0.2213707 0.21023796
##7 0.0010000 0.3149635 0.4110985 0.0010000 0.01272792
##9 0.3140143 0.0000000 0.1000000 0.3140143 0.30364453
请注意,此代码适用于任何 n > 1
。我们可以通过将 n
设置为 1
而不执行内部 rowSums
来恢复您之前的一维结果(因为 tmp$A
和 [=44 现在只有一列=]):
n <- 1 ## the number of dimensions, set this now to 1
tmp <- split(df[,1:n], df$class)
d <- sqrt(matrix(rowSums(expand.grid(tmp$B*tmp$B,tmp$A*tmp$A)),
nrow=length(tmp$B)) -
2. * as.matrix(tmp$B) %*% t(as.matrix(tmp$A)))
print(d)
## [,1] [,2] [,3] [,4] [,5]
##[1,] 0.003 0.295 0.395 0.003 0.005
##[2,] 0.598 0.300 0.200 0.598 0.590
##[3,] 0.198 0.100 0.200 0.198 0.190
##[4,] 0.001 0.299 0.399 0.001 0.009
##[5,] 0.298 0.000 0.100 0.298 0.290
这个问题是 how to extract intragroup and intergroup distances from a distance matrix? in R 的后续问题。在那个问题中,他们首先计算所有点的距离矩阵,然后简单地提取 inter-class 距离矩阵。我有一种情况,我想绕过初始计算并直接跳到提取,即我想直接计算 inter-class 距离矩阵。从链接示例中提取,通过调整,假设我在名为 df
:
values<-c(0.002,0.3,0.4,0.005,0.6,0.2,0.001,0.002,0.3,0.01)
class<-c("A","A","A","B","B","B","B","A","B","A")
df<-data.frame(values, class)
我想要的是距离矩阵:
1 2 3 8 10
4 .003 .295 .395 .003 .005
5 .598 .300 .200 .598 .590
6 .198 .100 .200 .198 .190
7 .001 .299 .399 .001 .009
9 .298 .000 .100 .298 .290
R 中是否已经存在一种优雅而快速的方法来做到这一点?
编辑 在收到上述一维案例的良好解决方案后,我想到了一个额外的问题:高维案例呢,如果改为 df
看起来像这样:
values1<-c(0.002,0.3,0.4,0.005,0.6,0.2,0.001,0.002,0.3,0.01)
values2<-c(0.001,0.1,0.1,0.001,0.1,0.1,0.001,0.001,0.1,0.01)
class<-c("A","A","A","B","B","B","B","A","B","A")
df<-data.frame(values1, values2, class)
我有兴趣再次获得 class B
中的点与 class A
.[=18= 中的点之间的欧氏距离矩阵]
这里尝试生成每个组合,然后简单地从每个值中取差:
abs(matrix(Reduce(`-`, expand.grid(split(df$values, df$class))), nrow=5, byrow=TRUE))
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0.003 0.295 0.395 0.003 0.005
#[2,] 0.598 0.300 0.200 0.598 0.590
#[3,] 0.198 0.100 0.200 0.198 0.190
#[4,] 0.001 0.299 0.399 0.001 0.009
#[5,] 0.298 0.000 0.100 0.298 0.290
对于一般的 n
维欧氏距离,我们可以利用方程(不是 R,而是代数):
square_dist(b,a) = sum_i(b[i]*b[i]) + sum_i(a[i]*a[i]) - 2*inner_prod(b,a)
其中总和超过向量 a
和 b
的维度,对于 i=[1,n]
。这里,a
和 b
是 A
和 B
中的一对。这里的关键是,这个方程可以写成 A
和 B
.
在代码中:
## First split the data with respect to the class
n <- 2 ## the number of dimensions, for this example is 2
tmp <- split(df[,1:n], df$class)
d <- sqrt(matrix(rowSums(expand.grid(rowSums(tmp$B*tmp$B),rowSums(tmp$A*tmp$A))),
nrow=nrow(tmp$B)) -
2. * as.matrix(tmp$B) %*% t(as.matrix(tmp$A)))
备注:
- 内部
rowSums
为B
中的每个b
和A
中的每个a
计算sum_i(b[i]*b[i])
和sum_i(a[i]*a[i])
,分别 expand.grid
然后生成B
和A
之间的所有对。- 外部
rowSums
计算所有这些对的sum_i(b[i]*b[i]) + sum_i(a[i]*a[i])
。 - 然后将此结果重塑为
matrix
。注意这个矩阵的行数就是你要求的classB
的点数 - 然后减去所有对的内积的两倍。这个内积可以写成矩阵乘法
tmp$B %*% t(tmp$A)
,为了清楚起见,我省略了对矩阵的强制转换。 - 最后,取平方根。
将此代码与您的数据一起使用:
print(d)
## 1 2 3 8 10
##4 0.0030000 0.3111688 0.4072174 0.0030000 0.01029563
##5 0.6061394 0.3000000 0.2000000 0.6061394 0.59682493
##6 0.2213707 0.1000000 0.2000000 0.2213707 0.21023796
##7 0.0010000 0.3149635 0.4110985 0.0010000 0.01272792
##9 0.3140143 0.0000000 0.1000000 0.3140143 0.30364453
请注意,此代码适用于任何 n > 1
。我们可以通过将 n
设置为 1
而不执行内部 rowSums
来恢复您之前的一维结果(因为 tmp$A
和 [=44 现在只有一列=]):
n <- 1 ## the number of dimensions, set this now to 1
tmp <- split(df[,1:n], df$class)
d <- sqrt(matrix(rowSums(expand.grid(tmp$B*tmp$B,tmp$A*tmp$A)),
nrow=length(tmp$B)) -
2. * as.matrix(tmp$B) %*% t(as.matrix(tmp$A)))
print(d)
## [,1] [,2] [,3] [,4] [,5]
##[1,] 0.003 0.295 0.395 0.003 0.005
##[2,] 0.598 0.300 0.200 0.598 0.590
##[3,] 0.198 0.100 0.200 0.198 0.190
##[4,] 0.001 0.299 0.399 0.001 0.009
##[5,] 0.298 0.000 0.100 0.298 0.290