web-dev-qa-db-fra.com

comment calculer la norme euclidienne d'un vecteur dans R?

J'ai essayé norm, mais je pense que cela donne le mauvais résultat. (la norme de c(1, 2, 3) est sqrt(1*1+2*2+3*3), mais elle renvoie 6 ..

x1 <- 1:3
norm(x1)
# Error in norm(x1) : 'A' must be a numeric matrix
norm(as.matrix(x1))
# [1] 6
as.matrix(x1)
#      [,1]
# [1,]    1
# [2,]    2
# [3,]    3
norm(as.matrix(x1))
# [1] 6

Quelqu'un sait-il quelle est la fonction pour calculer la norme d'un vecteur dans R?

36
Hanfei Sun

C'est une fonction triviale pour vous écrire:

norm_vec <- function(x) sqrt(sum(x^2))
45
joran
norm(c(1,1), type="2")     # 1.414214
norm(c(1, 1, 1), type="2")  # 1.732051
54
Bernd Elkemann

J'ai été surpris que personne n'ait essayé de profiler les résultats pour les méthodes suggérées ci-dessus, alors je l'ai fait. J'ai utilisé une fonction uniforme aléatoire pour générer une liste et l'ai utilisée pour la répétition (juste un simple dos du type d'enveloppe de référence):

> uut <- lapply(1:100000, function(x) {runif(1000, min=-10^10, max=10^10)})
> norm_vec <- function(x) sqrt(sum(x^2))
> norm_vec2 <- function(x){sqrt(crossprod(x))}
> 
> system.time(lapply(uut, norm_vec))
   user  system elapsed 
   0.58    0.00    0.58 
> system.time(lapply(uut, norm_vec2))
   user  system elapsed 
   0.35    0.00    0.34 
> system.time(lapply(uut, norm, type="2"))
   user  system elapsed 
   6.75    0.00    6.78 
> system.time(lapply(lapply(uut, as.matrix), norm))
   user  system elapsed 
   2.70    0.00    2.73 

Il semble que prendre la puissance puis sqrt manuellement soit plus rapide que le norm intégré pour les vecteurs de valeurs réelles au moins. C'est probablement parce que la norme fait en interne un SVD:

> norm
function (x, type = c("O", "I", "F", "M", "2")) 
{
    if (identical("2", type)) {
        svd(x, nu = 0L, nv = 0L)$d[1L]
    }
    else .Internal(La_dlange(x, type))
}

et la fonction SVD convertit en interne le vecteur en matrice, et fait des choses plus compliquées:

> svd
function (x, nu = min(n, p), nv = min(n, p), LINPACK = FALSE) 
{
    x <- as.matrix(x)
    ...
12
AbdealiJK
norm(x, type = c("O", "I", "F", "M", "2"))

La valeur par défaut est "O".

"O", "o" Ou "1" Spécifie la seule norme, (somme maximale absolue des colonnes);

"F" ou "f" spécifie la norme Frobenius (la norme euclidienne de x traitée comme s'il s'agissait d'un vecteur);

norm(as.matrix(x1),"o")

Le résultat est 6, identique à norm(as.matrix(x1))

norm(as.matrix(x1),"f")

Le résultat est sqrt(1*1+2*2+3*3)

Donc, norm(as.matrix(x1),"f") est la réponse.

12
stata

Nous pouvons également trouver la norme comme:

Result<-sum(abs(x)^2)^(1/2)

OU même vous pouvez également essayer comme:

Result<-sqrt(t(x)%*%x)

Les deux donneront la même réponse

2
Saurabh

Je vais aussi lancer ça comme une expression R équivalente

norm_vec(x) <- function(x){sqrt(crossprod(x))}

Ne confondez pas le crossprod de R avec un vecteur de même nom/ produit croisé . Cette dénomination est connue pour causer confusion surtout pour ceux qui ont une formation en physique/mécanique.

2
jxramos

Si vous avez un data.frame ou un data.table 'DT' et que vous souhaitez calculer la norme euclidienne (norme 2) sur chaque ligne, la fonction apply peut être utilisée.

apply(X = DT, MARGIN = 1, FUN = norm, '2')

Exemple:

>DT 

        accx       accy       accz
 1: 9.576807 -0.1629486 -0.2587167
 2: 9.576807 -0.1722938 -0.2681506
 3: 9.576807 -0.1634264 -0.2681506
 4: 9.576807 -0.1545590 -0.2681506
 5: 9.576807 -0.1621254 -0.2681506
 6: 9.576807 -0.1723825 -0.2682434
 7: 9.576807 -0.1723825 -0.2728810
 8: 9.576807 -0.1723825 -0.2775187

> apply(X = DT, MARGIN = 1, FUN = norm, '2')
 [1] 9.581687 9.582109 9.581954 9.581807 9.581932 9.582114 9.582245 9.582378
1
ilyas

Suite à la réponse d'AbdealiJK,

J'ai expérimenté davantage pour avoir un aperçu.

En voici un.

x = c(-8e+299, -6e+299, 5e+299, -8e+298, -5e+299)
sqrt(sum(x^2))
norm(x, type='2')

Le premier résultat est Inf et le second est 1.227355e+300 ce qui est tout à fait correct comme je vous le montre dans le code ci-dessous.

library(Rmpfr)
y <- mpfr(x, 120)
sqrt(sum(y*y))    

Le résultat est 1227354879.... Je n'ai pas compté le nombre de numéros de fin, mais tout semble correct. Je connais un autre moyen de contourner ce problème OVERFLOW qui consiste d'abord à appliquer la fonction de journalisation à tous les nombres et à les résumer, que je n'ai pas le temps de mettre en œuvre!

0
KH Kim

Créez votre matrice comme étau de colonne en utilisant cbind puis la fonction norm fonctionne bien avec la norme Frobenius (la norme euclidienne) comme argument.

x1 <-cbind (1: 3)

norme (x1, "f")

[1] 3,741657

sqrt (1 * 1 + 2 * 2 + 3 * 3)

[1] 3,741657

0
subash m