Utiliza el Matriz para almacenar la matriz, y el paquete skmeans_xdist para calcular distancias coseno.
/edit: Parece que el skmeans_xdist
no es muy eficaz. He aquí un ejemplo sencillo de cómo se calcularía la similitud del coseno para una matriz del tamaño de Netflix en R.
Primero, construye la matriz:
library(Matrix)
set.seed(42)
non_zero <- 99000000
i <- sample(1:17770, non_zero, replace=TRUE)
j <- sample(1:480189, non_zero, replace=TRUE)
x <- sample(1:5, non_zero, replace=TRUE)
m <- sparseMatrix(i=i,j=j,x=x) #Rows are movies, columns are users
m <- drop0(m)
A continuación, normalice cada fila para que su distancia vectorial sea 1. Esto tarda 85 segundos en mi máquina.
row_norms <- sqrt(rowSums(m^2))
row_norms <- t(crossprod(sign(m), Diagonal(x=row_norms)))
row_norms@x <- 1/row_norms@x
m_norm <- m * row_norms
Por último, podemos encontrar la similitud coseno, que me lleva 155 segundos
system.time(sim <- tcrossprod(m_norm))
Obsérvese también que la matriz de similitud coseno es bastante dispersa, porque muchas películas no tienen ningún usuario en común. Puede convertir a distancia coseno utilizando 1-sim
pero puede tardar un poco (no lo he cronometrado).
/editar un par de años después: Aquí hay una función de normalización de filas más rápida:
row_normalize <- function(m){
row_norms <- sqrt(rowSums(m^2))
row_norms <- t(crossprod(sign(m), Diagonal(x=row_norms)))
row_norms@x <- 1/row_norms@x
m_norm <- m * row_norms
return(m_norm)
}
fast_row_normalize <- function(m){
d <- Diagonal(x=1/sqrt(rowSums(m^2)))
return(t(crossprod(m, d)))
}
library(microbenchmark)
microbenchmark(
a = row_normalize(m),
b = fast_row_normalize(m),
times=1
)
La nueva función sólo tarda 25 segundos (frente a los 89 segundos de la otra, supongo que mi ordenador se ha vuelto más lento =/):
Unit: seconds
expr min lq mean median uq max neval
a 89.68086 89.68086 89.68086 89.68086 89.68086 89.68086 1
b 24.09879 24.09879 24.09879 24.09879 24.09879 24.09879 1