script perl - Perl - Programmation
Marsh Posté le 14-05-2013 à 17:41:34
Bonjour,
Ça doit pas être très dur, mais il faudrait
1) expliquer ce que fait chaque ligne de ton script (je connais pas le R, et une ligne comme ceci: Files_res[[i]]<-assign(i, read.delim(filepath,head=T) m'est pas directement compréhensible, vu que je ne connais pas la notation [[ ]] ou la fonction assign)
2) coller qques lignes d'un de tes fichiers de départ, que je puisse faire un peu de test si nécessaire et en particulier, une ligne de début de fichier (ou il y a les en-tête).
Si je devine bien avec ma boule de crystal, dans un répertoire donné, vous filtrez les fichier en extension .txt, vous récupérez une liste des noms (sans extension) de ces fichiers (noms tous en 5 caractères?), et on arrive à la ligne avec le assign...
A+,
Marsh Posté le 17-05-2013 à 04:19:34
A priori, ceci devrait le faire, aux différences de la dernière décimale du log2 près
Code :
|
A+,
Marsh Posté le 17-05-2013 à 13:29:26
use Cwd; |
On va aller faire le travail dans le répertoire cible, puis revenir au répertoire de départ une fois le travail terminé.
Manifestement, le programme R se coltine des noms complets, ce qui n'a aucun intérêt:
filepath <- file.path("/Volumes/EQ15_SM",paste(i,".txt",sep="" ))
my @flist = glob("*.txt" ); |
On récupère avec glob la liste des fichiers en .txt du répertoire, et on va travailler un par un sur chacun (foreach...)
On saute les fichiers commençant par un . (j'ai pas testé l'expression régulière /^[^.].*\.txt$/ car windows XP n'accepte pas les fichiers commençant avec un . apparement mais elle devrait être bonne.) Si je saute ces fichiers, c'est parce que j'ai lu que la fonction R qui est utilisée le faisait
filenames<-dir("/Volumes/EQ15_SM",pattern="\\.txt" )
my $outfile = $infile =~ s/^(.*)(\.txt)$/${1}_final${2}/r; |
Je construis le nom du fichier de sortie en insérant _final dans le nom du fichier d'entrée
Le code R fait des choses qui sont un peu inutiles ou complexes, qui exploitent le fait que les fichier ont des noms de exactement 5 caractères avant l'extension:
names_files<-substr(filenames,1,5)
...
write.table(Files_fin[[i]], paste(names(Files_fin)[i], ".pc", sep = "" ),
C'est avec une extension .pc que c'est fait ici et non _final.txt
Si vous voulez un nom de fichier résultat avec .pc, il suffit de changer mon code en:
my $outfile = $infile =~ s/^(.*)(\.txt)$/${1}.pc/r;
open(my $infh, '<', $infile); |
On ouvre en lecture le fichier d'entrée, en écriture celui de sortie, et on les ferme après traitement
while (my $line = <$infh> ) { |
On lit le fichier ligne a ligne et on traite chaque ligne.
D'abord on vire le retour a la ligne final, puis on découpe la ligne comme des champs de texte séparés par des tabulations.
if ($. == 1) { |
Si c'est la première ligne ($. == 1), on récupère les indices des champs utiles: les 3 premiers (0..2)et ceux qui démarrent par BB ou BP (/^B(B|P)/)
On ne conserve alors que les champs utiles: @cols = @cols[@outcols];
On cherche maintenant parmi eux les indices de ceux contenant raw (c'est ceux dont on va transformer la valeur avec log2)
On remplace ensuite le texte des têtes de colonne (ie les champs de cette première ligne) par les valeurs voulues en sortie.
else { |
Si ce n'est pas la première ligne, on filtre pour ne garder que les champs attendus en sortie: @cols = @cols[@outcols];
Et pour ceux qui ont besoin du remplacement par le log de la valeur, on fait ce remplacement.
La ligne @cols = map {looks_like_number($_)?0+$_:$_} @cols; c'est pour que en sortie, Perl se comporte comme R:
Quand Perl lit un champ avec 1.48844e+07, pour lui, c'est du texte, et il va l'écrire comme il l'a lue. En effectuant une addition avec 0, Perl va dorénavant considérer le champ comme un nombre et l'écrire 14884400 en sortie (comme le fait R)
print $outfh join("\t", @cols), "\n"; |
On écrit les champs utiles et éventuellement modifiés dans le fichier de sortie.
A+,
Marsh Posté le 17-05-2013 à 15:19:26
J'ai eu ce message d'erreur
Can't locate autodie.pm in @INC (@INC contains: /Library/Perl/Updates/5.8.8 /System/Library/Perl/5.8.8/darwin-thread-multi-2level /System/Library/Perl/5.8.8 /Library/Perl/5.8.8/darwin-thread-multi-2level /Library/Perl/5.8.8 /Library/Perl /Network/Library/Perl/5.8.8/darwin-thread-multi-2level /Network/Library/Perl/5.8.8 /Network/Library/Perl /System/Library/Perl/Extras/5.8.8/darwin-thread-multi-2level /System/Library/Perl/Extras/5.8.8 /Library/Perl/5.8.6 /Library/Perl/5.8.1 .) at /users/sourour/desktop/essai/convert2penncnv.pl line 7.
BEGIN failed--compilation aborted at /users/sourour/desktop/essai/convert2penncnv.pl line 7.
Marsh Posté le 17-05-2013 à 16:36:15
C'est juste que vous n'avez pas le module autodie d'installé. Il faut dire que vous avez une version assez ancienne de Perl, dans les versions récentes il est installé en standard.
Plusieurs solutions:
- Mettez a jour votre version de Perl (la version courante est la 5.16 et vous utilisez la 5.8)
ou
- installez le module manquant (si c'est le perl de ActiveState, utiliser ppm, sinon, sur Mac, il faut sans doute passer pas cpan)
ou
- Supprimez le ligne
use autodie;
et remplacez les lignes
open(my $infh, '<', $infile);
open(my $outfh, '>', $outfile);
par
open(my $infh, '<', $infile) or die "cannot open $infile : $!";
open(my $outfh, '>', $outfile) or die "cannot open $outfile : $!";
Mais vous aurez de toute façon le même problème pour le module Scalar::Util et lui, il faudra bien que vous l'installiez de toute façon, car il n'est pas dans la distribution de base. Il y a ici un article anglais qui vous donne quelques principes de base pour utiliser cpan sur le Mac: http://www.macinstruct.com/node/463
EDIT: En y repensant, SI vous êtes sure que toutes les données (pour toutes les lignes sauf la première) sont toujours des valeurs numériques, sauf le premier champ en début de ligne (qui correspond à Name dans l'en tête), alors vous pouvez aussi supprimer la ligne
use Scalar::Util qw(looks_like_number);
et remplacer la ligne
@cols = map {looks_like_number($_)?0+$_:$_} @cols;
par
foreach (1..$#cols) {
$cols[$_] += 0;
}
Ce qui vous évitera d'installer le module Scalar::Util
A+,
Marsh Posté le 14-05-2013 à 17:03:47
Bonjour,
Serait il possible de m'aider à traduire un petit script de R en perl?
cdt,
voici le script en R;
#Lire l'ensemble de tes fichiers dans R
filenames<-dir("/Volumes/EQ15_SM",pattern="\\.txt" )
Files_res<-list()
names_files<-substr(filenames,1,5) # extraire le nom commun de tous tes fichiers
for(i in names_files){
filepath <- file.path("/Volumes/EQ15_SM",paste(i,".txt",sep="" ))
Files_res[[i]]<-assign(i, read.delim(filepath,head=T))
}
###Récupérer les colonnes 1:3 ainsi que les colonnes commencant par BB ou BP
noms<-colnames(Files_res[[1]]) # juste pour récupérer les noms de colonnes
start_with_BBorBP_3first <- noms %in% grep("^BB|^BP", noms, value=TRUE) | noms%in%noms[1:3]
Files_BBBP<-list()
for(i in 1:length(Files_res)){
Files_BBBP[[i]]<-subset(Files_res[[i]], ,start_with_BBorBP_3first)
}
#les nouveaux fichiers sont dans la liste Files_BBBP
# La fonction pour convertir en log2
logmatfunction<-function(M){
indic<-grep("raw",colnames(M))
M[,indic]<-log2(M[,indic])
return(M)
}
Files_fin<-list()
for(i in 1:length(Files_BBBP))
{
Files_fin[[i]]<-logmatfunction(Files_BBBP[[i]])
}
#Exporter tous les fichiers tranformés
names(Files_fin)<-names(Files_res)
## changer le nom des colonnes
for(i in 1:length(Files_fin))
{
colnames(Files_fin[[i]])[1:3]<-c("Name","Chr","pos" )
colnames(Files_fin[[i]])<-c(colnames(Files_fin[[i]])[1:3],gsub("\\ ","",paste(substr(gsub("\\.","", colnames(Files_fin[[i]]))[-c(1:3)],1,8),"",".Log R ratio" )))
}
for(i in seq_along(Files_fin)) {
write.table(Files_fin[[i]], paste(names(Files_fin)[i], ".pc", sep = "" ),
row.names = FALSE, sep = "\t", quote = FALSE)
}