Le calcul de toutes les distances entre un point et un groupe de points efficacement dans la R
Tout d'abord, je suis nouveau sur R (j'ai commencé hier).
J'ai deux groupes de points, data
et centers
, la première de taille n
et le second, de taille K
(par exemple, n = 3823
et K = 10
), et pour chaque i
dans le premier set, j'ai besoin de trouver j
dans la seconde, avec le minimum de distance.
Mon idée est simple: pour chaque i
, laissez dist[j]
la distance entre i
et j
, j'ai seulement besoin d'utiliser which.min(dist)
à trouver ce que je cherche.
Chaque point est un tableau de 64
doubles, de sorte
> dim(data)
[1] 3823 64
> dim(centers)
[1] 10 64
J'ai essayé avec
for (i in 1:n) {
for (j in 1:K) {
d[j] <- sqrt(sum((centers[j,] - data[i,])^2))
}
S[i] <- which.min(d)
}
qui est extrêmement lent (avec n = 200
, il faut plus de 40 ans!!). La solution la plus rapide que j'ai écrit est
distance <- function(point, group) {
return(dist(t(array(c(point, t(group)), dim=c(ncol(group), 1+nrow(group)))))[1:nrow(group)])
}
for (i in 1:n) {
d <- distance(data[i,], centers)
which.min(d)
}
Même si il fait beaucoup de calcul que je ne l'utilise pas (parce que dist(m)
calcule la distance entre toutes les lignes de m
), c'est plus rapide que l'autre (quelqu'un peut-il expliquer pourquoi?), mais il n'est pas assez rapide pour ce dont j'ai besoin, car il ne peut être utilisé qu'une seule fois. Et aussi, le distance
code est très laid. J'ai essayé de le remplacer par
distance <- function(point, group) {
return (dist(rbind(point,group))[1:nrow(group)])
}
mais ce qui semble être deux fois plus lentement. J'ai aussi essayé d'utiliser dist
pour chaque paire, mais il est aussi plus lent.
Je ne sais pas quoi faire maintenant. Il me semble que je suis en train de faire quelque chose de très mal. Aucune idée sur comment faire cela de manière plus efficace?
ps: j'en ai besoin pour mettre en œuvre des k-means à la main (et j'ai besoin de le faire, c'est le cadre d'une cession). Je crois que je vais seulement besoin de distance Euclidienne, mais je ne suis pas encore certain, donc je préfère avoir un peu de code où la distance de calcul peut être remplacé facilement. stats::kmeans
faire tout le calcul en moins d'une seconde.
OriginalL'auteur dbarbosa | 2010-06-12
Vous devez vous connecter pour publier un commentaire.
Plutôt que d'une itération à travers les points de données, vous pouvez condenser que pour un fonctionnement de la matrice, ce qui signifie que vous n'avez qu'à itérer à travers
K
.S'exécute dans:
sur mon ordinateur portable.
Je suis en train d'utiliser votre solution, mais votre matrice transposée. Est-il un moyen de soustraire les lignes comme vous l'avez fait avec des colonnes?
J'ai essayé la soustraction avec des lignes à l'aide de l'appliquer, mais il n'était pas si rapide que votre solution. Je suis maintenant à la transposition de la matrice et à l'aide de votre code, et il est vraiment rapide! Merci beaucoup!!! Et aussi, merci pour votre réponse complète avec un petit exemple et l'utilisation du système.temps. Merci beaucoup 🙂
OriginalL'auteur Jonathan Chang
que rdist() est une fonction R de {champs} package qui est capable de calculer la distance entre deux ensembles de points dans une matrice rapidement.
https://www.image.ucar.edu/~nychka/Fields/Help/rdist.html
Utilisation :
OriginalL'auteur Deuterium
Vous voudrez peut-être avoir un coup d'oeil dans le
apply
fonctions.Par exemple, ce code
Peut facilement être remplacé par quelque chose comme
Vous pouvez certainement l'optimiser plus, mais vous obtenez le point, je l'espère,
distance
.eh bien, apparemment, le
stats::kmeans
package utilise le code compilé qui est évidemment plus rapide. Tapez simplementkmeans
et vous allez voir le code source. 🙂OriginalL'auteur nico
dist
travaille vite parce que c'est pas vectorisé et d'appel interne les fonctions C.Vous de code dans la boucle pourrait être vectorisées dans de nombreuses façons.
Par exemple pour calculer la distance entre
data
etcenters
vous pouvez utiliserouter
:Cela vous donne
n x K
de la matrice de distances. Et devrait être de manière plus rapide que la boucle.Alors vous pouvez utiliser
max.col
pour trouver le maximum de chaque ligne (voir l'aide, il existe quelques nuances quand de nombreux maxima).X
doit être nier la cause que l'on recherche pour un minimum.Pour être efficace dans la R vous devriez vectorisé que possible. Boucles pourraient être dans de nombreux cas, remplacé par vectorisé substitut. Vérifiez l'aide pour
rowSums
(qui décrivent aussirowMeans
,colSums
,rowSums
),pmax
,cumsum
. Vous pourriez rechercher, par exemplehttps://stackoverflow.com/search?q=%5Br%5D+éviter de+boucle (copie&coller ce lien, je ne sais pas comment le rendre cliquable) pour des exemples.
system.time(outer(seq_len(n), seq_len(K), function(i,j) sqrt(rowSums((x[,i]-centers[,j])^2))))
, mais j'obtiens cette erreur:Error in dim(robj) <- c(dX, dY) : dims [product 38230] do not match the length of object [64]
voyez-vous quel est le problème?En fait je n'étais pas la compréhension
outer
(je pensais que c'était l'appel de la fonction une fois pour chaque paire). Maintenant, je suis à la comprendre, je vous remercie, il peut être utile! Et aussi, merci pour racontermax.col
.OriginalL'auteur Marek
Ma solution:
Vous pouvez l'essayer, comme:
OriginalL'auteur Adriano Rivolli