Unix - eliminer des colonnes .txt

Résolu
AlexMac -  
 AlexMac -
Bonjour a tous,

J'ai en input un fichier texte contenant
--at-gg---
--at-gga--
--at-gtcg-
--atgtgtt-

et je voudrais eliminer les colonnes contenant plus de 80% de -, afin d'obtenir :

atgg--
atgga-
atgtcg
attgtt

J'ai cherche beaucoup mais rien trouve. Peut etre la commande awk pour compter es occurences de - dans chaque colonne, mais je ne vois pas comment faire

Merci pour votre aide

Alexandre

4 réponses

  1. dubcek Messages postés 18627 Date d'inscription   Statut Contributeur Dernière intervention   5 659
     
    hello
    la colonne 5 contient moins de 80% de -, c'est pour cela que je teste <75
    $ cat a1
    --at-gg---
    --at-gga--
    --at-gtcg-
    --atgtgtt-
    $ 
    $ awk '{x[NR]=$0}END{for(i=1;i<=10;i++){for(n=1;n<=NR;n++){if(substr(x[n],i,1)=="-")c[i]++} ;col[i]=(100*c[i])/NR} ; for(n=1;n<=NR;n++){for(i=1;i<=10;i++){if(col[i]<75)printf substr(x[n], i, 1)} print ""}}' a1
    atgg--
    atgga-
    atgtcg
    attgtt
    $ 
    $ 
    1
    1. AlexMac
       
      Merci beacoup dubcek,

      Ca marche a merveille!

      Je vais essayer de décortiquer pour comprendre, mais j'avoue que quelques explication seraient les bienvenues.

      Merci encore beaucoup

      Alex
      0
    2. dubcek Messages postés 18627 Date d'inscription   Statut Contributeur Dernière intervention   5 659
       
      même code, mais dans un fichjier avec indentations
      # on lit le fichirer en entier qu'on stocke dans un tableau x
      {x[NR]=$0}
      END{
      # pour chaque colonne (ici 10) de chaque ligne (NR == nb de lignes), on
      # compte le nombre de -,  nombre que l'on stocke dans un tableau c
              for(i=1;i<=10;i++){
                      for(n=1;n<=NR;n++){
                              if(substr(x[n],i,1)=="-")
                                      c[i]++} ;
      # on a le nombre de - par colonne, on peut calculer le %
                              col[i]=(100*c[i])/NR
              } ;
      # pour chaque ligne et chaque colonne, on teste si le % de cette colonne
      # est < 75, si oui on imprime le caractère
                              for(n=1;n<=NR;n++){
                                      for(i=1;i<=10;i++){
                                              if(col[i]<75)
                                                      printf substr(x[n], i, 1)
                                      }
      # on imprime un saut de ligne en fin de ligne
                                      print ""
                              }
      }
      
      
      0
  2. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     
    En fait si je résume cette longue discussion c'est que le pourcentage seuil (80%) est relatif à chaque colonne, ce qui force à lire l'ensemble des lignes pour savoir si la colonne est conservée ou non.

    À mon avis il n'y a pas quarante solutions, il faut lire toutes les lignes, les stocker en mémoire, et parcourir la structure ainsi lue. A peu près n'importe quel langage de programmation permet de le faire.

    Personnellement je fais plutôt du C++, mais si tu préfères le python ou n'importe quoi d'autre pourquoi pas...

    Source (toto.cpp)
    #include <fstream>
    #include <vector>
    #include <iostream>
    #include <string>
    
    int main(int argc, char **argv){
    	const char *filename_in  = argv[1],
                   *filename_out = argv[2];
    
    	const unsigned int num_chars = 10; // Chaque ligne valide doit comporter 10 caractères
    	const unsigned int threshold = 80; // 80 %
    	unsigned int num_lines = 0;
    
    	std::string line;
    
    	std::ifstream ifs;
    	std::ofstream ofs;
    
    	std::vector<std::string> lines;
    	std::vector<unsigned int> num_minus(num_chars, 0);
    	std::vector<bool> column_to_write(num_chars);
    
    	if(argc != 3) {
    		std::cerr << "usage: " << argv[0] << " input_file output_file" << std::endl;
    		goto END;
    	}
    
    	// Ouvrir le fichier d'entrée
    	ifs.open(filename_in);
    	if(!ifs) {
    		std::cerr << argv[0] << ": can't read " << filename_in << std::endl;
    		goto END;
    	}
    
    	// Ouvrir le fichier de sortie 
    	ofs.open(filename_out);
    	if(!ofs) {
    		std::cerr << argv[0] << ": can't write " << filename_out << std::endl;
    		goto END;
    	}
    
    	// Charger les lignes en mémoire et compter le nombre de '-'
    	while(std::getline(ifs, line)) {
    		if(line.size() == num_chars){
    			for(std::size_t i = 0; i < num_chars; ++i){
    				if(line[i] == '-') ++num_minus[i];
    			}
    			lines.push_back(line);
    			++num_lines;
    		}
    	}
    
    	// Quelles colonnes doit on réécrire ?
    	for(std::size_t i = 0; i < num_chars; ++i){
    		column_to_write[i] = ((100 * num_minus[i] / num_lines) < threshold);
    	}
    
    	// Écrire les lignes en ne conservant que le nécessaire 
    	for(std::size_t i = 0; i < lines.size(); ++i){
    		for(std::size_t j = 0; j < num_chars; ++j){ 
    			if(column_to_write[j]){
    				ofs << lines[i][j];
    			}
    		}
    		ofs << std::endl;
    	}
    
    END:
    	// On ferme proprement
    	if(ifs) ifs.close();
    	if(ofs) ofs.close();
    	return 0;
    }
    


    Avec ce fichier d'entrée (input.txt) :

    --at-gg---
    --at-gga--
    --at-gtcg-
    --atgtgtt-


    Il faut à présent installer un compilateur (par exemple g++ sous linux ou code::blocks sous windows). Par exemple sous linux (ubuntu, debian...) :

    sudo apt-get update
    sudo apt-get install g++


    On compile notre programme (appelons le par exemple convertir.exe) :

    (mando@aldur) (~) $ g++ -W -Wall toto.cpp -o convertir.exe
    (mando@aldur) (~) $ ./convertir input.txt output.txt


    On obtient le fichier output.txt :

    at-gg--
    at-gga-
    at-gtcg
    atgtgtt


    ... ce qui est le bon résultat si j'ai bien pigé.

    À l'époque tu avais dit que normalement la sortie était :

    atgg--
    atgga-
    atgtcg
    attgtt 


    ... mais la colonne qui contient (-,-,-,g) contient seulement 75% de '-' soit moins de 80%, donc normalement on la conserve...

    Bonne chance
    1
    1. AlexMac
       
      Merci Mamiemando pour cette reponse,
      Je vais prendre le temps d'essayer cela. Cela dit, le script propose par dubcek marche bien et il est assez simple.
      Tu as raison je me suis plante pour la colonne (- - - g) ;-/ Desole
      Merci encore Beaucoup
      Alex
      0
  3. zipe31 Messages postés 34620 Date d'inscription   Statut Contributeur Dernière intervention   6 501
     
    Salut,

    Rien pigé à ton histoire de 80% ;-((

    Sur la ligne 2, pourquoi t'élimines les 2 premiers et qu'un seul sur les 2 derniers ???
    --at-gga-- => atgga- 
    0
    1. AlexMac
       
      En fait il faut lire en colonne :
      la premiere colonne ne contient que des - (donc 100% de -), elle degage
      la deuxieme idem
      la troisieme ne contient pas de - (il n'a que des a), elle reste
      etc
      l'avant dernier ne contient que deux - (et un g et un t), donc elle reste (50% de -)
      et la derniere ne contient que des -, elle degage

      J'espere avoir reussi a etre clair cette fois

      Merci

      Alex
      0
    2. zipe31 Messages postés 34620 Date d'inscription   Statut Contributeur Dernière intervention   6 501
       
      En fait il faut lire en colonne
      Ok, mais à quoi reconnaît-on une colonne ???
      0
    3. AlexMac
       
      bah oui c un des probleme.
      Si je veux utiliser awk je peux par exemple ajouter des pipes (|) apres chaque caracteres.
      genre sed "s/./|/g"

      C'est pas trop un soucis vu que je pourrais les retirer ensuite
      0
    4. zipe31 Messages postés 34620 Date d'inscription   Statut Contributeur Dernière intervention   6 501
       
      Tes explications sont complètement incohérentes ;-((

      la premiere colonne ne contient que des - (donc 100% de -), elle degage
      la deuxieme idem

      En considérant que chaque caractère est en fait une colonne à lui tout seul, nous sommes d'accord ;-\

      la troisieme ne contient pas de - (il n'a que des a), elle reste
      etc

      Idem qu'au-dessus ;-\

      l'avant dernier ne contient que deux - (et un g et un t), donc elle reste (50% de -)
      C'est là où ça se corse ;-((
      Pourquoi subitement ta colonne contient plusieurs caractères et commence à mélanger caractères alphanumériques avec des caractères non-alphanumériques ???

      Où est la logique dans tout ça ??? ;-\
      0
    5. AlexMac
       
      il s'agit de sequences d'ADN (succession de molecules A T C et G pour Adenosine, Guanine, Thymine, Custeine) qui sont alignees selon leur similarite, imaginons:

      gene humain ATGCT - -TCGCT
      gene mouche ATGCTTGTCGCT
      gene meduse ATCGT - -TCGCT

      Ces genes sont identiques chez les trois organismes (humain, mouche , meduse), sauf que dans la sequence genetique de la mouche, il y a deux molecules en plus, un T et un G.
      Ce molecules absente chez l'homme et la meduse sont representes par des tirets.

      Ce que je voudrais c'est conserver cet alignement tou en eliminant les zones contenant beaucoup de tirets, c'est a dire les zones genetiques peu conservees entre differentes especes.

      Voila, j'espere que c'est plu clair pour toi

      Alex
      0
  4. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     
    Oui tu peux t'en sortir avec awk.

    man awk


    $0 désigne la ligne courante, affecte là à s.
    length(s) permet de calculer la longueur de s.
    Crée un compteur (par exemple num_minus) initialisé à 0.
    Dans une boucle for allant de 0 à length(s) - 1 :
    - substr(s, i, 1) permet d'extraire le i-ème caractère.
    - si c'est un tiret, incrémente ton compteur num_minus
    Une fois la boucle for, calcule le pourcentage (100 * num_minus / length(s)). S'il est supérieur à ton seuil de 80, print $0.

    Bonne chance
    0
    1. AlexMac
       
      OK je vais essayer, mais j'ai l'impression que dans ce que tu me suggere, ce sont les - sur les lignes qui sont comptes, et non sur les colonnes. C'est justement ca qui me pose probleme.
      Alex
      0