2012-03-26 21 views
17

R'de bir temel/ortak sınıf "dist" olarak adlandırılır ve simetrik bir uzaklık matrisinin nispeten verimli bir temsilidir. Bununla birlikte, "matrix" nesnesinin aksine,örneğinin "[" işlecini kullanarak dizin çiftleri tarafından işlenmesi için destek görünmemektedir./Özellikle işlemek, aşağıdaki komutlar bir anlamda, işi, ancak erişim için hiç kolay yapmazlar aradaÇekirdek R? Kullanarak bir "dist" sınıfı örneğinin öğelerini nasıl kullanabilirim/erişebilirim?

# 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] 

:

Örneğin, aşağıdaki kod şey, NULL veya bir hata döndürür indeks-pair değerler:

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 

bir geçici çözüm - Ben önlemek istiyorum - öncelikle bir "matrix" için "dist" nesneyi dönüştürdüğünü matrisi işlemek ve sonrageri dönüştürmek olduğunu 10 Bu, question about how to convert a "dist" örneğinin bir "matrix" örneğine veya ortak matris indeksleme araçlarının zaten tanımlandığı başka bir sınıf olmadığı anlamına da gelir; Bu bir different SO question

çeşitli şekillerde cevap beri stats pakette araçlar var mı (ya da belki başka bir çekirdek R paketi) adanmış indeksleme/"dist" örneği unsurlarını erişen?

+1

İyi S: Sizin için bir cevabınız yok, ancak R'de bir matrisin sadece boyutları olan bir vektör olduğunu unutmayın. Bu yüzden, 'dist1 [1:20] 've' dist1 [5] <- 100' ve benzeri işler düzgün değildir. Küçük bir sorunla, atomlara aşinam sınırlı olsa da, muhtemelen iki boyutlu bir versiyon yazabilirsin. –

cevap

5

Sorunuz için doğru bir cevabım yok, ancak Euclidian mesafesini kullanıyorsanız, fields paketinden rdist işlevine bakın. Uygulaması (Fortran'da), dist'dan daha hızlıdır ve çıktı, matrix sınıfındadır. En azından, bazı geliştiricilerin bu dist sınıfından uzaklaşmayı seçtiklerini, belki de bahsettiğiniz kesin nedenlerden dolayı olduğunu gösterir. Simetrik bir matrisi depolamak için tam matrix kullanmanın verimsiz bir bellek kullanımı olduğundan endişe ediyorsanız, onu üçgen matrisine dönüştürebilirsiniz. as.dist(m) bir dist nesnesine geri matris m dönecek ise

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 
+0

Teşekkürler! Bu bilmek için yararlıdır. Ve R'deki temel “dist” -handling araçlarının oldukça spartan olduğunu bilmek yardımcı olur. –

2

as.matrix(d), bir matris içine dist nesne d dönecek. İkincisinin, m'un geçerli bir mesafe matrisi olduğunu kontrol etmediğini unutmayın; Alt üçgen parçasını çıkarır.

+0

Bu cevabın sorumuzdan daha önce (Son paragraf ve '(dist1," matrix "gibi) kodda belirtilmişti. Bu çözümden ayrı olarak" yerinde "bir çözüm olup olmadığını merak ediyorum - - '' dist '' sınıfı R. tarafından desteklenir. '' as.dist' '' nin '' dist 'örneğinin geçerliliğini kontrol etmediği konusundaki yorumunuz için teşekkürler… –

+0

Farkı görmüyorum. matris stili indeksleme için * bir 'dist 'nesnesinde' as.matrix' kullanmak için * 'dır: 'as.matrix' jenerik çağrıları' stats ::: as.matrix.dist'; Sınıf –

+0

Sorunun sonunu açıklığa kavuşturmaya çalıştım.Ben karışıklık ben atıfta herhalde "yerinde" ifade belirsizlik kaynaklanıyor düşünüyorum ya (1) istediğim sınıf flip-flop gibi bazı sebepten ötürü istenmeyen yaklaşımlar da dahil olmak üzere Ar zaten herhangi araçları, kaçınmak; veya (2) bu amaç için ayrılmış bir araç ve geçici olarak bile görevi tamamlamak için nesnemin sınıfını değiştirmeyecek sınıf. –

0

Bunu yapabilirsiniz: Bunu sağlayacak

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 

Ancak, diyagonal veya üst üçgen yaptığınız tüm değişiklikler dikkate alınmaz. Bu yapılacak doğru şey olabilir veya olmayabilir. Değilse, bu tür durumlar için bir çeşit akıl sağlığı kontrolü veya uygun muamele eklemeniz gerekir. Ve muhtemelen başkaları.

+0

Teşekkürler Tyler. Bu hala bir sınıf flip-flop (akıllı ve kullanışlı olsa da) gibi görünmektedir; bu da orijinal '' dist ''örneğindeki' $ call' gibi potansiyel yararlı özelliklerin bazılarını öldürme potansiyeline de sahip olabilir. Ben de aşağıda yazmış olduğum cevap hakkında ne düşündüğünüzü merak ediyorum; bu, sınıfı değiştirmeyen bir çalışma erişimcisinin yanı sıra henüz çözmediğim, çalışmayan bir değiştirme işlevini de içeriyor. –

+0

@Paul, çözümünüz iyi görünüyor, ancak bir nedenden dolayı çaprazlar için yanlış değer döndürüyor. Değiştirme işlevinin neden çalışmadığını bilmiyorum. – Tyler

0

Bunun için stats paketinde araçlar görünmüyor. Çekirdek olmayan bir pakette alternatif bir uygulama için @flodel'e teşekkürler.

Bu soruda sorduğum gibi,sınıfı çekirdek R kaynağında, dist.R kaynak dosyasında hiçbir araç bulunmayan eski okul S3 tanımına kazdım.

dist() fonksiyon belgelerine işaret etmez, uygun şekilde, (ve teklif):

bir vektör içinde sütunlar tarafından depolanan uzaklık matrisinin alt üçgen, do demek. n gözlem sayısı, örneğin, n <- attr(do, "Size") ise, o zaman I < j ≤ n, (satır) i ve j arasındaki benzerlikleri olan:

do[n*(i-1) - i*(i-1)/2 + j-i]

vektörünün uzunluğu, yani n*(n-1)/2 olup, Siparişin n^2.

(son alıntı)

bir tanımlamak kendin "dist" erişimci Aşağıdaki örnek bu kodu yararlandı. Bu örnekteki her seferinde yalnızca bir değer döndürülebileceğini unutmayın.

################################################################################ 
# 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)]] 
} 
################################################################################ 

Ve bu beklendiği gibi iyi çalışıyor gibi görünüyor. Bununla birlikte, değiştirme işlevini çalışmaya çalışırken sorun yaşıyorum.

################################################################################ 
# Define the replacement function 
################################################################################ 
"[.dist<-" <- function(x, i, j, value){ 
    x[[get.dist.index(x, i, j)]] <- value 
    return(x) 
} 
################################################################################ 

Bu yeni görevi operatör

dist1["5", "3"] <- 7000 

döndürür bir test işletilen:

"R> Hata dist1["5", "3"] <- 7000 içinde: matrisi üzerinde simgelerin doğru numarası"

sorular olarak- Bence, @flodel soruyu daha iyi cevapladı, ama yine de bu "cevap" ın da yararlı olabileceğini düşündü.

Ayrıca, bu geçerli örnekten kolayca uyarlanabilen, Matrix package modelinde kare-destekli erişim ve değiştirme tanımlarının bazı güzel S4 örneklerini buldum.

8

Maalesef bunu yapmanın standart yolları yoktur. İşte, 1D indeksi ile 2D matris koordinatlarına dönüşen iki fonksiyon. Güzel değiller ama işe yarıyorlar ve en azından, ihtiyacınız varsa daha güzel bir şey yapmak için kodu kullanabilirsiniz. Ben sadece bunu yayınlar denklemler açık değildir.

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) 
} 

küçük bir test koşum

çalıştığını göstermek için:

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] 
+0

Bu, çoğunlukla yararlı bir yanıttır, ancak amaçlanan uygulama göz önüne alındığında, bir miktar açıklama gerektirmektedir. Sadece çalışırsam çalışır. I = j ve i> j için yanlış cevabı verir. Distdex işlevini değiştirmek için i == j iken 0 ve i ve j transpoze ederken i> j problemi çözdüğümde kodu koydum, böylece diğerleri kopyalayıp yapıştırabilsin. Net olmak gerekirse, bu yalnızca standart dışı sorgulamalarla ilgili bir meseledir, bu yüzden Christian A'nın bir kazısı sadece bir açıklama değildir. – csfowler

0

dist nesneler hemen hemen aynı yolu gibi basit vektör nesneleri davranılır görünüyor. Özelliklerine sahip bir vektörünü görebildiğim kadarıyla. Böylece değerleri almak için:

x = as.vector(distobject) 

See? Belirli bir nesne çifti arasındaki mesafeyi kendi endekslerini kullanarak ayıklamak için bir formül için dist.

+0

Bu (zorlama) diğer cevaplarda daha önce tanımlanmıştı ve soruda kaçınmaya çalışıyorum. Matrix stilinde en az bir çeşit çıkarma veya atama girişimi yapan bazı kodları da tercih ederim. "" ["Gösterimi değerli bir cevaptır. –

1

Bunu yararlı bulabilirsiniz [from ??dist]: Elde edilen matris 35K tarafından 35K olacağından

The lower triangle of the distance matrix stored by columns in a vector, say ‘do’. If ‘n’ is the number of observations, i.e., ‘n <- attr(do, "Size")’, then for i < j <= n, the dissimilarity between (row) i and j is ‘do[n*(i-1) - i*(i-1)/2 + j-i]’. The length of the vector is n*(n-1)/2, i.e., of order n^2.

+0

Kısmi cevabım formülü uzun bir süre içeriyor. Bu soruyu SO'ya göndermeden çok önce yaptığım ilk şey '' dist '' de doktora gitmekti. –

0

bir matris dönüştürülüyor, benim için söz konusu olamaz da, bu yüzden bulmak için bir işlevi bir vektör olarak (dist sonucunu) bıraktı ve yazdım vektöründe yer mesafe olmalıdır burada: X ve Y, sen dist hesaplanan olan matris içinde elemanlarının orjinal sıralarını ve n

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) 

} 

bu toplam eleman sayısı matris. Sonuç, mesafenin nerede olacağı dist vektöründe konumdur. Umarım mantıklıdır.

1

Bu yanıt, gerçekten Christian A'nın daha önceki yanıtlarına yönelik genişletilmiş bir takiptir. Sorunun bazı okuyucularından (kendimi dahil ettiğim için), doğru nesneyi simetrik sanki (sadece (7,13) değil, aynı zamanda (13,7) gibi sorgulayabildikleri garantidir. Düzenleme ayrıcalıklarına sahip değilim. Daha önceki cevap doğruydu, kullanıcı dist nesnesi dist nesnesi olarak değil de bir seyrek bir matris olarak davranıyordu, bu yüzden bir düzenleme yerine ayrı bir cevabım var. Bu cevap işe yararsa ağır yükü kaldırmak için Christian A'yı oylayın . yapıştırılan benim düzenlemelerle orijinal cevap:

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 

Ama ...

distdex(13,7,20) # =156 
testd[156] #the wrong answer 

Christian A'nın işlevi yalnızca eserleri eğer ben < j. I = j ve i> j için yanlış cevabı verir. Sen str()

ile herhangi bir nesnenin atributes acces

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 
2

i j == ve i> j yüzden sorun çözer zaman i ve j aktarması zaman distdex fonksiyonunu değiştirme 0 dönmek benim bazı verilerin (dist1) bir "dist" nesnesi için, bu gibi bakmak:

> 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) 

bu özel veri seti için olduğunu görebilirsiniz "Etiketler" özelliği uzunlukta bir karakter dizesidir = 96 1'den 96'ya kadar rakamlarla karakterler.

doğrudan yapıyor bu karakter dizisini değiştirebilir:

> attr(dist1,"Labels") <- your.labels 

"your.labels" Bazı kimliği olmalıdır. ya da faktör vektörü, muhtemelen "dist" nesneden gelen orijinal verilerde yapılmıştır.

İlgili konular