R中的基本/公共类称为"dist"
,是对称距离矩阵的相对有效表示。但是,与"matrix"
对象不同,似乎不支持使用"dist"
运算符通过索引对操纵"["
实例。
例如,以下代码不返回任何内容,NULL
或错误:
# First, create an example dist object from a matrix
mat1 <- matrix(1:100, 10, 10)
rownames(mat1) <- 1:10
colnames(mat1) <- 1:10
dist1 <- as.dist(mat1)
# Now try to access index features, or index values
names(dist1)
rownames(dist1)
row.names(dist1)
colnames(dist1)
col.names(dist1)
dist1[1, 2]
同时,在某种意义上,以下命令确实有效,但是不要使访问/操作特定索引对值更容易:
dist1[1] # R thinks of it as a vector, not a matrix?
attributes(dist1)
attributes(dist1)$Diag <- FALSE
mat2 <- as(dist1, "matrix")
mat2[1, 2] <- 0
我想避免的解决方法是首先将"dist"
对象转换为"matrix"
,操纵该矩阵,然后将其转换回"dist"
。也就是说,这不是"dist"
"matrix"
实例到stats
,或其他类已经定义了常见的矩阵索引工具;因为在question about how to convert
"dist"
包中(或者某些其他核心R包)中的工具是否专用于{{1}}实例的索引/访问元素?
答案 0 :(得分:8)
遗憾的是,没有标准的方法可以做到这一点。这是两个函数,它们将1D索引转换为2D矩阵坐标。它们并不漂亮,但它们可以工作,至少你可以使用代码在你需要的时候制作更好的东西。我发布它只是因为方程不明显。
distdex<-function(i,j,n) #given row, column, and n, return index
n*(i-1) - i*(i-1)/2 + j-i
rowcol<-function(ix,n) { #given index, return row and column
nr=ceiling(n-(1+sqrt(1+4*(n^2-n-2*ix)))/2)
nc=n-(2*n-nr+1)*nr/2+ix+nr
cbind(nr,nc)
}
一个小测试工具,以显示它的工作原理:
dist(rnorm(20))->testd
as.matrix(testd)[7,13] #row<col
distdex(7,13,20) # =105
testd[105] #same as above
testd[c(42,119)]
rowcol(c(42,119),20) # = (3,8) and (8,15)
as.matrix(testd)[3,8]
as.matrix(testd)[8,15]
答案 1 :(得分:5)
我对您的问题没有直接的答案,但如果您使用欧几里德距离,请查看rdist
包中的fields
函数。它的实现(在Fortran中)比dist
快,输出是类matrix
。至少,它表明一些开发人员选择放弃这个dist
类,可能是因为你提到的确切原因。如果您担心使用完整的matrix
存储对称矩阵是对内存的低效使用,您可以将其转换为三角矩阵。
library("fields")
points <- matrix(runif(1000*100), nrow=1000, ncol=100)
system.time(dist1 <- dist(points))
# user system elapsed
# 7.277 0.000 7.338
system.time(dist2 <- rdist(points))
# user system elapsed
# 2.756 0.060 2.851
class(dist2)
# [1] "matrix"
dim(dist2)
# [1] 1000 1000
dist2[1:3, 1:3]
# [,1] [,2] [,3]
# [1,] 0.0000000001 3.9529674733 3.8051198575
# [2,] 3.9529674733 0.0000000001 3.6552146293
# [3,] 3.8051198575 3.6552146293 0.0000000001
答案 2 :(得分:4)
as.matrix(d)
会将dist
对象d
转换为矩阵,而as.dist(m)
会将矩阵m
变回dist
个对象。请注意,后者实际上并未检查m
是否为有效距离矩阵;它只是提取下三角形部分。
答案 3 :(得分:3)
您可以使用str()
访问任何对象的属性对于&#34; dist&#34;我的一些数据(dist1)的对象,它看起来像这样:
> str(dist1)
Class 'dist' atomic [1:4560] 7.3 7.43 7.97 7.74 7.55 ...
..- attr(*, "Size")= int 96
..- attr(*, "Labels")= chr [1:96] "1" "2" "3" "4" ...
..- attr(*, "Diag")= logi FALSE
..- attr(*, "Upper")= logi FALSE
..- attr(*, "method")= chr "euclidean"
..- attr(*, "call")= language dist(x = dist1)
你可以看到,对于这个特定的数据集,&#34;标签&#34; attribute是一个长度= 96的字符串,数字从1到96作为字符。
您可以直接更改该字符串:
> attr(dist1,"Labels") <- your.labels
&#34; your.labels&#34;应该是一些id。或者因子矢量,可能是来自&#34; dist&#34;的原始数据。对象是。
答案 4 :(得分:1)
您可能会发现这有用[来自?? dist]:
由a中的列存储的距离矩阵的下三角形 矢量,说'做'。如果'n'是观察的数量,即'n&lt; - attr(do,“Size”)',然后是i&lt; j&lt; = n,之间的差异 (行)i和j是'do [n *(i-1) - i *(i-1)/ 2 + j-i]'。的长度 向量是n *(n-1)/ 2,即n ^ 2阶。
答案 5 :(得分:1)
这一回应实际上只是对Christian A早期回应的延伸。这是有道理的,因为问题的一些读者(包括我自己)可能会将dist对象视为对称(不仅仅是(7,13)如下,还有(13,7)。我没有编辑权限和早期的答案是正确的,只要用户将dist对象视为dist对象而不是稀疏矩阵,这就是为什么我有一个单独的响应而不是编辑。如果这个答案很有用,请投票给Christian A进行繁重的工作。 。 我编辑的原始答案粘贴在:
distdex<-function(i,j,n) #given row, column, and n, return index
n*(i-1) - i*(i-1)/2 + j-i
rowcol<-function(ix,n) { #given index, return row and column
nr=ceiling(n-(1+sqrt(1+4*(n^2-n-2*ix)))/2)
nc=n-(2*n-nr+1)*nr/2+ix+nr
cbind(nr,nc)
}
#A little test harness to show it works:
dist(rnorm(20))->testd
as.matrix(testd)[7,13] #row<col
distdex(7,13,20) # =105
testd[105] #same as above
但是...
distdex(13,7,20) # =156
testd[156] #the wrong answer
Christian A的功能只有在i&lt;学家对于i = j和i&gt; j它返回错误的答案。当i == j时修改distdex函数以返回0并且当i> =时转换i和j。 j解决了这个问题:
distdex2<-function(i,j,n){ #given row, column, and n, return index
if(i==j){0
}else if(i > j){
n*(j-1) - j*(j-1)/2 + i-j
}else{
n*(i-1) - i*(i-1)/2 + j-i
}
}
as.matrix(testd)[7,13] #row<col
distdex2(7,13,20) # =105
testd[105] #same as above
distdex2(13,7,20) # =105
testd[105] #the same answer
答案 6 :(得分:0)
你可以这样做:
d <- function(distance, selection){
eval(parse(text = paste("as.matrix(distance)[",
selection, "]")))
}
`d<-` <- function(distance, selection, value){
eval(parse(text = paste("as.matrix(distance)[",
selection, "] <- value")))
as.dist(distance)
}
这将允许您这样做:
mat <- matrix(1:12, nrow=4)
mat.d <- dist(mat)
mat.d
1 2 3
2 1.7
3 3.5 1.7
4 5.2 3.5 1.7
d(mat.d, "3, 2")
[1] 1.7
d(mat.d, "3, 2") <- 200
mat.d
1 2 3
2 1.7
3 3.5 200.0
4 5.2 3.5 1.7
但是,您对对角线或上三角形所做的任何更改都将被忽略。这可能是也可能不是正确的做法。如果不是,您需要为这些案例添加某种健全性检查或适当的处理。还有其他人。
答案 7 :(得分:0)
stats
包中似乎没有工具。感谢@flodel在非核心软件包中的替代实现。
我挖掘了核心R源代码中"dist"
类的定义,这是一个老式的S3,在dist.R
源文件中没有工具,就像我在这个问题中所询问的那样
dist()
函数的文档确实指出了(并且我引用):
距离矩阵的下三角形,由向量中的列存储,例如do
。如果n
是观察的数量,即n <- attr(do, "Size")
,那么对于i&lt; j≤n,(行)i
和j
之间的差异是:
do[n*(i-1) - i*(i-1)/2 + j-i]
向量的长度为n*(n-1)/2
,即n^2
的顺序。
(结束语)
我在以下示例代码中利用了这个来定义自己的"dist"
访问器。请注意,此示例一次只能返回一个值。
################################################################################
# Define dist accessor
################################################################################
setOldClass("dist")
getDistIndex <- function(x, i, j){
n <- attr(x, "Size")
if( class(i) == "character"){ i <- which(i[1] == attr(x, "Labels")) }
if( class(j) == "character"){ j <- which(j[1] == attr(x, "Labels")) }
# switch indices (symmetric) if i is bigger than j
if( i > j ){
i0 <- i
i <- j
j <- i0
}
# for i < j <= n
return( n*(i-1) - i*(i-1)/2 + j-i )
}
# Define the accessor
"[.dist" <- function(x, i, j, ...){
x[[getDistIndex(x, i, j)]]
}
################################################################################
这似乎正如预期的那样正常。但是,我无法让替换功能起作用。
################################################################################
# Define the replacement function
################################################################################
"[.dist<-" <- function(x, i, j, value){
x[[get.dist.index(x, i, j)]] <- value
return(x)
}
################################################################################
这个新赋值运算符的测试运行
dist1["5", "3"] <- 7000
返回:
dist1["5", "3"] <- 7000
中的“R&gt;错误:矩阵”
根据问题,我认为@flodel更好地回答了这个问题,但仍然认为这个“答案”也可能有用。
我还在Matrix package中找到了方括号访问器和替换定义的一些不错的S4示例,可以很容易地从当前示例中进行调整。
答案 8 :(得分:0)
似乎dist对象的处理方式与简单的矢量对象几乎相同。据我所知,它的属性为矢量。所以要取出价值:
x = as.vector(distobject)
请参阅? dist用于公式,使用它们的索引提取特定对象对之间的距离。
答案 9 :(得分:0)
转换为矩阵对我来说也是不可能的,因为得到的矩阵将是35K乘35K,所以我把它作为向量(dist的结果)并写了一个函数来找到向量中的位置距离应为:
distXY <- function(X,Y,n){
A=min(X,Y)
B=max(X,Y)
d=eval(parse(text=
paste0("(A-1)*n -",paste0((1:(A-1)),collapse="-"),"+ B-A")))
return(d)
}
在提供X和Y的情况下,矩阵中元素的原始行从中计算出dist,n是该矩阵中元素的总数。结果是距离将在dist矢量中的位置。我希望这是有道理的。
答案 10 :(得分:0)
答案 11 :(得分:0)
这是我通过名称从dist对象获取值的实用解决方案。是否希望将第9项作为值的向量?
as.matrix(mat1)[grepl("9", labels(mat1))]