Manipulation d'un très longue liste

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Christian Dina
Messages : 40
Enregistré le : 18 Jan 2007, 12:36

Manipulation d'un très longue liste

Messagepar Christian Dina » 31 Jan 2007, 15:03

Bonjour,

comem c'est mon premier message, je me présente : je travailel en statistique génétique à Lille.
Comme mes questions l'attesteront, je suis débutant en R (et en gros je programme un peu en R comme si c'était du - mauvais - PERL :D ).

J'ai fait un fonction qui génére une liste extrémement longue (en gros toutes les paires de variables avec leurs correlations - mais avec beaucoup de variables - autour de 5000).

lorsque j'appelle la liste
> listeGen

Ca va encore.
Si par contre j'appelle
> do.call(rbind,listeGen)
pour l'avoir sous forme de matrice, R n'est pas content.

Savez-vous s'il existe une solution pour écrire directement dans un fichier
(car en fait je n'ai pas besoin de créer de liste) ou s'il y a un moyen plus
"économique" pour stocker cete matrice de corrélation en ligne.

Merci d'avance

Christian Dina

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Messagepar Logez Maxime » 31 Jan 2007, 16:06

Bonjour,


Effectivement tu peux écrire directement dans un fichier sans passer par une liste tout dépend de ton script. Je te conseille de regarder du côté de la fonction write.table qui te permets d'écrire dans un fichier texte par exemple ce fichier pouvant être créer ou étendu avec le paramètre append = FALSE ou TRUE, ça peut être un moyen plutôt que de stocker tes résultats dans une liste avec autant d'éléments.

En espérant t'avoir aidé un peu.

Maxime

Olivier Delaigue
Messages : 220
Enregistré le : 05 Déc 2006, 07:38

Messagepar Olivier Delaigue » 31 Jan 2007, 16:07

Si j'ai bien compris la forme des données, moi, je n'ai pas de problème avec le do.call (et la sortie au format .txt ou .xls n'est alors pas forcément utile)

Code : Tout sélectionner

> t_list<-rep(list(sample(1:10000,size=3)),5000)
> t_list[1:2]
[[1]]
[1] 5766 9644 2244

[[2]]
[1] 5766 9644 2244

> t_mat<-do.call("rbind",t_list)
> t_mat[1:10,]
      [,1] [,2] [,3]
 [1,] 5766 9644 2244
 [2,] 5766 9644 2244
 [3,] 5766 9644 2244
 [4,] 5766 9644 2244
 [5,] 5766 9644 2244
 [6,] 5766 9644 2244
 [7,] 5766 9644 2244
 [8,] 5766 9644 2244
 [9,] 5766 9644 2244
[10,] 5766 9644 2244

> write.table(t_mat,"t_mat.txt",sep="\t",row.names=F)
> write.table(t_mat,"t_mat.xls",sep="\t",row.names=F)

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Messagepar Logez Maxime » 31 Jan 2007, 16:13

Re,


Pour ce qui est du moyen "economique" je te conseille de directement mettre tes résultats dans une matrice, mais il est difficile de te conseiller quoique ce soit sans avoir une idée un peu plus précise de la manière dont sont générées tes données (avec une boucle, avec une fonction ...)

Maxime

Renaud Lancelot
Messages : 2484
Enregistré le : 16 Déc 2004, 08:01
Contact :

Messagepar Renaud Lancelot » 31 Jan 2007, 18:27

Si par contre j'appelle
> do.call(rbind,listeGen)
pour l'avoir sous forme de matrice, R n'est pas content.


Je pense que c'est une coquille, mais l'appel doit être:

Code : Tout sélectionner

do.call("rbind", listeGen)

(avec des quotes à "rbind").

Comme indiqué par Maxime, ça ira bcp plus vite si les composantes de listeGen sont des matrices et non des data.frames. Cela peut avoir un inconvénient si les données sont de différents types (numérique, caractère,...) mais il est facile de rétablir le type correct en transformant la matrice finale en data.frame.

Si la lenteur est due à la constitution de la liste elle-même, on peut accélérer sensiblement les choses en créant une liste contenant des composantes vides, du style:

Code : Tout sélectionner

listeGen <- vector(mode = "list", length = n)

où n est le nombre attendu de composantes (peut être un majorant de la vraie longueur). Ensuite, on remplit la liste dans une boucle for().

Une alternative possible est de constituer la liste dans une commande by() avec une fonction ad hoc (voir l'argument FUN de by).

Renaud

Christian Dina
Messages : 40
Enregistré le : 18 Jan 2007, 12:36

Merci

Messagepar Christian Dina » 01 Fév 2007, 11:33

Merci poru vos réponses.

1/ il y avait une typo, c'était bien do.call("rbind",....)

Sinon, les données sont générées sous forme de boucle que voilà :

listeGen <- list()
k=1;
for (i in 1:500) {
for (j in 1:i-1) {
listeGen[[k]] <- c(i,j,cor(toto[i],toto[j],use="pairwise.complete.obs"));k=k+1;
}
}


3/ Passer dans une matrice.
En fait c'est ce que je voulais faire au début sauf que je ne suis pas arrivé à le faire (débutant). C'est sur les conseils d'un R-eur chevronné (hello Jacques si tu es là) que je suis passé à cette procédure (mais à l'époque il s'agissait d'un ensemble de données + petites).


Christian

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Messagepar Logez Maxime » 01 Fév 2007, 13:12

Bonjour,


De la même façon que tu crées ta liste tu peux créer un objet "vide" qui te servira de conteneur pour avoir au final l'ensemble de tes résultats dans une seule matrice :

Code : Tout sélectionner

# soit res le contenant
res <- NULL
for (i in 1:500) {
for (j in 1:i-1) {
u <- c(i,j,cor(toto[i],toto[j],use="pairwise.complete.obs"));k=k+1;
res <- rbind(res,u)
}
}
is.matrix(res)

De cette façon a chaque itération "res" va s'agrandir en lignes de ton vecteur u.
Je ne sais pas si c'est la façon la plus économique mais je pense que tu devrais obtenir le même résultat.
Une autre possibilité serait de créer une matrice res au départ qui soit de la taille finale des résultats et ensuite d'indexer dans res le résultat de chaque itération. Je ne sais pas ce qui est les plus long en terme de calcul ou ce qui prend le plus de mémoire.

A voir.

Maxime

Renaud Lancelot
Messages : 2484
Enregistré le : 16 Déc 2004, 08:01
Contact :

Messagepar Renaud Lancelot » 01 Fév 2007, 18:07

Code : Tout sélectionner

# soit res le contenant
res <- NULL
for (i in 1:500) {
for (j in 1:i-1) {
u <- c(i,j,cor(toto[i],toto[j],use="pairwise.complete.obs"));k=k+1;
res <- rbind(res,u)
}
}
is.matrix(res)


Cela va être très long, la partie "rbind" étant très inefficace dans ce cas. D'autre part, is.matrix(res) renvoie un scalaire logique. Peut-être avez-vous voulu écrire as.matrix(res) ?

Si je comprends bien le code, l'objectif est de calculer la corrélation entre toutes les colonnes d'une matrice. Pourquoi ne pas utiliser simplement:

Code : Tout sélectionner

cor(toto)


ce qui est remarquablement rapide même pour de très grosses matrices:

Code : Tout sélectionner

> mat <- matrix(runif(100000), ncol = 5000)
> system.time(cormat <- cor(mat))
[1] 2.06 0.11 2.17   NA   NA
>
> dim(cormat)
[1] 5000 5000


(Soit environ 2 secondes pour calculer la matrice de corrélation d'une matrice de 200 lignes et 5000 colonnes.)

Renaud

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Messagepar Logez Maxime » 02 Fév 2007, 15:03

Bonjour,



Une question que l'on peut se poser est effectivement la nature de toto, car ici dans ton exemple on ne voit pas ce que ça peut être une matrice un array ? parce que tel que dans l'exemple toto[i] et toto[j] ferait référence a une seule valeur.

Peux-tu nous donner un peu plus de détails concernant toto.

Maxime

Christian Dina
Messages : 40
Enregistré le : 18 Jan 2007, 12:36

Détails toto et pourquoi pas cov

Messagepar Christian Dina » 07 Fév 2007, 16:44

En fait j'ai essayé dernièrement cov (qui est en effet très rapide).

SEulement, étant vraiement très mauvais en manip de données en R, je ne voyais pas facilement comment passer de la matrice à un liste (car en gros j'ai besoin ensuite de la distribution des coeffs (donc j'en ai besoin en colonne).

Pour ce qui est de toto : mon idée initiale était que ce soit une matrice, simplement j'ai repris un code qui s'appliquait à une liste plus petite.

L'idée étai d'avoir une matrice avec l'identificaiton des paires (indiv 1, indiv 2) et la coeff de correlation (corr).

Voilà,

j'espère avoir été clair.


Christian

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Messagepar Logez Maxime » 07 Fév 2007, 21:33

Bonsoir,


Je ne sais pas si je vais vraiment répondre a ta question mais je te propose le script suivant qui peut t'être utile:

Code : Tout sélectionner

x <- matrix(rnorm(25),5,5,dimnames=list(as.integer(1:5),as.integer(1:5)))
x
            1          2          3          4          5
1  0.18931202 -0.4579587  1.1740275 -0.4429264 -0.8397508
2  1.54449168 -0.8151885  0.5258326 -1.4049701  0.9094203
3 -0.02694955  1.3195234 -0.4664256 -0.4533051  0.2409488
4  2.59261257  0.2499363  1.2673197 -0.7765437  0.6929546
5 -1.27171641 -1.0478090  0.9086384 -1.9094488  1.3978522
corx <- cor(x,use="pairwise.complete.obs")
corx
            1          2          3          4           5
1  1.00000000  0.1843643  0.2646658  0.3109222 -0.03874729
2  0.18436433  1.0000000 -0.6331019  0.7350265 -0.29892993
3  0.26466577 -0.6331019  1.0000000 -0.2024142 -0.04581440
4  0.31092224  0.7350265 -0.2024142  1.0000000 -0.83933118
5 -0.03874729 -0.2989299 -0.0458144 -0.8393312  1.00000000
class(corx) <- "table"
lower <- as.vector(lower.tri(corx))
corx <- as.data.frame.table(corx)
corx <- as.matrix(corx)
corx <- corx[lower,]
corx <- corx[,c(2,1,3)]
corx # une matrice de charactère mais pas de soucis pour la passée en nombre
   Var2 Var1 Freq         
2  "1"  "2"  " 0.18436433"
3  "1"  "3"  " 0.26466577"
4  "1"  "4"  " 0.31092224"
5  "1"  "5"  "-0.03874729"
8  "2"  "3"  "-0.63310194"
9  "2"  "4"  " 0.73502654"
10 "2"  "5"  "-0.29892993"
14 "3"  "4"  "-0.20241423"
15 "3"  "5"  "-0.04581440"
20 "4"  "5"  "-0.83933118"

J'ai testé la même chose avec une matrice 500*500 et ça m'a pris 7 secondes avec mon portable centrino 1.7 1go ram.

En espérant t'avoir aidé.

Maxime

Christian Dina
Messages : 40
Enregistré le : 18 Jan 2007, 12:36

Super

Messagepar Christian Dina » 09 Fév 2007, 10:19

C'est exactement le script qu'il me fallait. Merci beaucoup.

Christian


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité