2
votes

effectuer le calcul sur toutes les combinaisons de colonnes d'une matrice

J'essaie d'appliquer une fonction à une très grande matrice Je veux créer éventuellement une matrice ( 40 000 x 40 000 ) (où un seul côté de la diagonale est complété) ou créer une liste les résultats.

La matrice ressemble à:

List <- list()
for(i in 1:ncol(mat))
{
  temp <- List[[i]] <- mat
}

res <- List[1][[1]]
res

J'utilise la fonction en utilisant cosinus (mat [ 3], mat [ 4]) code> qui me donne un seul chiffre.

co <- matrix(0L, nrow = ncol(mat), ncol = ncol(mat), dimnames = list(colnames(mat), colnames(mat)))
co

for (i in 2:ncol(mat)) {
  for (j in 1:(i - 1)) {
    co[i, j] = cosine(mat[, i], mat[, j])
  }
}

co

Je peux faire ça pour toutes les colonnes mais je veux pouvoir savoir de quelles colonnes elles proviennent, c'est à dire le calcul ci-dessus proviennent des colonnes 3 et 4 qui sont "obs 3" et "obs 4" . p >

La sortie attendue peut être les résultats dans une liste ou une matrice comme:

#generate some data

mat <- matrix(data = runif(200), nrow = 100, ncol = 20, dimnames = list(paste("words", 1:100),
                                                                        paste("obs", 1:20)))


mat


#calculate the following function
library(lsa)
cosine(mat[, 3], mat[, 4])
cosine(mat[, 4], mat[, 5])
cosine(mat[, 5], mat[, 6])

(Où les nombres ici sont constitués)

Donc les dimensions seront la taille du ncol (mat) par ncol (mat) (si j'utilise la méthode de la matrice).

Data / Code :

          [,1]   [,1]   [,1]
[1,]        1      .      .
[1,]      0.75     1      .
[1,]      0.23    0.87    1

Supplémentaire

J'ai pensé à faire ce qui suit: - Créer une matrice vide et calculer la fonction dans un forloop mais cela ne fonctionne pas comme prévu et créer une matrice 40 000 par 40 000 de 0 soulève des problèmes de mémoire.

          [,1]
[1,] 0.7546113


0 commentaires

4 Réponses :


2
votes

Une option consiste à définir une fonction à appliquer pour deux colonnes, puis à utiliser externe pour appliquer à toutes les combinaisons de colonnes.

fun <- function(x, y) {
   cosine(mat[, x], mat[, y])
}

outer(seq_len(ncol(mat)), seq_len(ncol(mat)), Vectorize(fun))

#       [,1]   [,2]   [,3]   [,4]   [,5]  ..... 
#[1,] 1.0000 0.7824 1.0000 0.7824 1.0000 .....
#[2,] 0.7824 1.0000 0.7824 1.0000 0.7824 .....
#[3,] 1.0000 0.7824 1.0000 0.7824 1.0000 .....
#[4,] 0.7824 1.0000 0.7824 1.0000 0.7824 .....
#[5,] 1.0000 0.7824 1.0000 0.7824 1.0000 .....
#....


2 commentaires

Merci! Cela fonctionne, et cela fonctionne bien sur certaines autres données et donne les résultats corrects, mais sur les données complètes, j'obtiens les mêmes problèmes de mémoire Erreur: impossible d'allouer un vecteur de taille 7,1 Go . Je devrais peut-être diviser les données en morceaux et les calculer ...


@ user113156 oui, cela vous donne cette erreur si les données sont trop volumineuses pour tenir dans la mémoire disponible. Il existe de nombreux articles disponibles si vous recherchez sur Google ce message d'erreur expliquant comment gérer efficacement ces énormes données. L'un d'eux est ici stackoverflow.com/questions/5171593/...



1
votes

Nous pouvons le faire avec une sapply

i1 <- seq_len(ncol(mat))
sapply(i1, function(i) sapply(i1, function(j) cosine(mat[, i], mat[, j])))    #         [,1]      [,2]      [,3]      [,4]      [,5]      [,6]      [,7]      #[,8]      [,9]     [,10]     [,11]     [,12]
# [1,] 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016
# [2,] 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000
# [3,] 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016
# [4,] 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000
# [5,] 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016
# [6,] 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000
# [7,] 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016 1.0000000 0.7849016
# ....

imbriquée


1 commentaires

Merci! J'ai mis mat <- Matrix (mat, sparse = TRUE) pour rendre les choses plus rapides et il fonctionne. Je n'ai aucune idée si cela causera des problèmes de mémoire comme les tentatives précédentes, mais son traitement et je vous ferai connaître les résultats. Pourquoi cette méthode «semble-t-elle» fonctionner alors que mes autres tentatives ont échoué? Que se passe-t-il à l'intérieur de R?



2
votes

1) En utilisant mat indiqué dans la question, la première ligne crée une matrice 20x20 avec tous les cosinus 20 * 20 remplis. La deuxième ligne met à zéro les valeurs sur et au-dessus de la diagonale. Utilisez plutôt lower.tri si vous préférez que les valeurs sur et en dessous de la diagonale soient à zéro.

co6 <- crossprod(scale(mat)) / (nrow(mat) - 1)
co6[upper.tri(co6, diag = TRUE)] <- 0

2) Alternativement pour créer un vecteur numérique nommé des résultats:

library(propagate)
co5 <- mult * bigcor(mat)
co5[upper.tri(co5, diag = TRUE)] <- 0

3) Nous pouvons utiliser le fait que les cosinus hors diagonale sont les mêmes que les corrélations jusqu'à un facteur, mult.

library(HiClimR)
co4 <- mult * fastCor(mat)
co4[upper.tri(co4, diag = TRUE)] <- 0

3a) Cela s'ouvre en utilisant l'une des nombreuses fonctions de corrélation disponibles dans R . Par exemple, en utilisant mult vient de calculer:

mult <- c(cosine(mat[, 1], mat[, 2]) / cor(mat[, 1], mat[, 2]))
co3 <- mult * cor(mat)
co3[upper.tri(co3, diag = TRUE)] <- 0

3b)

covec <- c(combn(as.data.frame(mat), 2, function(x) c(cosine(x[, 1], x[, 2]))))
names(covec) <- combn(colnames(mat), 2, paste, collapse = "-")


2 commentaires

Ouais pour un langage vectorisé!


Merci! votre première méthode cosinus (mat m'a donné l'erreur impossible d'allouer de la mémoire vectorielle . Votre deuxième méthode voit fonctionner, j'exécute actuellement la méthode @akrun pour le moment, J'exécuterai votre deuxième méthode dès qu'elle sera terminée et vous le ferai savoir.



0
votes

Nous pouvons utiliser l'itération sur les index en utilisant purrr (comme meilleure alternative (?) aux boucles for). Je pense que le jeu de données du jouet était censé contenir 2000, et non 200 points de données?

library(tidyverse)

mat <-
  matrix(
    data = runif(2000),
    nrow = 100,
    ncol = 20,
    dimnames = list(paste("words", 1:100),
                    paste("obs", 1:20))
  )

cos_summary <- tibble(Row1 = 3:5, Row2 = 4:6)

cos_summary <- cos_summary %>%
  mutate(cos_1_2 = map2_dbl(Row1, Row2, ~lsa::cosine(mat[,.x], mat[,.y])))

cos_summary

# A tibble: 3 x 3
   Row1  Row2 cos_1_2
  <int> <int>   <dbl>
1     3     4   0.710
2     4     5   0.734
3     5     6   0.751


0 commentaires