2013-01-24 7 views
3

J'ai un énorme fichier texte (19 Go de taille); c'est un fichier de données génétiques avec des variables et des observations.
La première ligne contient les noms de variables et ils sont structurés comme suit:Remplacer le texte dans la première ligne dans un énorme fichier délimité par des tabulations txt

id1.var1 id1.var2 id1.var3 id2.var1 id2.var2 id2.var3 

J'ai besoin d'échanger ID1, ID2 ect. avec les valeurs correspondantes qui sont dans un autre fichier texte (ce fichier a environ 7k lignes) ids ne sont pas dans un ordre particulier et il est structuré comme suit:

oldId newIds 
id1 rs004 
id2 rs135 

Je l'ai fait une recherche google et ne pouvait pas vraiment trouver une langue qui permettrait de faire ce qui suit:

  1. lire la première ligne
  2. remplacer les ids avec les nouveaux ids
  3. enlever la première ligne du fichier d'origine et de le remplacer par le nouveau

Est-ce une bonne approche ou existe-t-il une meilleure approche?
Quel est le meilleur langage pour accomplir ceci?
Nous avons des personnes avec de l'expérience en python, vbscipt et Perl.

Répondre

1

Cela devrait être assez facile. Je voudrais utiliser Python comme je suis un fan de Python. Contour:

  • Lisez le fichier de mappage et enregistrez le mappage (en Python, utilisez un dictionnaire).

  • Lisez le fichier de données une ligne à la fois, remappez les noms de variables et affichez la ligne éditée.

Vous ne pouvez vraiment pas modifier un fichier en place ... hmm, je suppose que vous pourriez, si chaque nouveau nom de la variable était toujours exactement la même longueur que l'ancien nom. Mais pour faciliter la programmation et la sécurité pendant l'exécution, il est préférable de toujours écrire un nouveau fichier de sortie, puis de supprimer l'original. Cela signifie que vous aurez besoin d'au moins 20 Go d'espace disque libre avant de l'exécuter, mais cela ne devrait pas poser de problème.

Voici un programme Python qui montre comment le faire. J'ai utilisé vos données d'exemple pour faire des fichiers de test et cela semble fonctionner.

#!/usr/bin/python 

import re 
import sys 

try: 
    fname_idmap, fname_in, fname_out = sys.argv[1:] 
except ValueError: 
    print("Usage: remap_ids <id_map_file> <input_file> <output_file>") 
    sys.exit(1) 

# pattern to match an ID, only as a complete word (do not match inside another id) 
# match start of line or whitespace, then match non-period until a period is seen 
pat_id = re.compile("(^|\s)([^.]+).") 

idmap = {} 

def remap_id(m): 
    before_word = m.group(1) 
    word = m.group(2) 
    if word in idmap: 
     return before_word + idmap[word] + "." 
    else: 
     return m.group(0) # return full matched string unchanged 

def replace_ids(line, idmap): 
    return re.sub(pat_id, remap_id, line) 

with open(fname_idmap, "r") as f: 
    next(f) # discard first line with column header: "oldId newIds" 
    for line in f: 
     key, value = line.split() 
     idmap[key] = value 

with open(fname_in, "r") as f_in, open(fname_out, "w") as f_out: 
    for line in f_in: 
     line = replace_ids(line, idmap) 
     f_out.write(line) 
+0

merci beaucoup! Je vais montrer ce code à mon programmeur. Merci –

4

L'ensemble « remplacer » chose est possible dans presque toutes les langues (je suis sûr sur Python et Perl), aussi longtemps que la longueur de la ligne de remplacement est le même que le d'origine, ou si il peut être fait par padding avec des espaces (sinon, vous devrez réécrire le fichier entier).

Ouvrez le fichier pour la lecture et l'écriture (mode w+), lire la première ligne, préparer la nouvelle ligne, seek position 0 dans le fichier, écrire la nouvelle ligne, fermez le fichier.

+0

Cela pourrait ne pas fonctionner si "id1" => "rs004". Donc, il pourrait y avoir le seul moyen d'écrire un nouveau fichier. – alex

+0

Merci. Je cours actuellement un code Python qui fait ce que vous avez suggéré. Les ID n'ont pas la même longueur et le fichier doit être réécrit. Je suis dans un environnement Windows et cela peut prendre des heures à fonctionner. J'espère que ca fonctionne. –

3

Je vous suggère d'utiliser le module Tie::File, qui mappe les lignes dans un fichier texte à un tableau Perl et rendra la réécriture des lignes après l'en-tête un travail simple.

Ce programme illustre.Il lit d'abord tous les anciens/nouveaux ID dans un hachage, puis mappe le fichier de données en utilisant Tie::File. La première ligne du fichier (dans $file[0]) est modifiée à l'aide d'une substitution, puis le tableau est détaché pour réécrire et fermer le fichier.

Vous devrez changer vos noms de fichiers par rapport à ceux que j'ai utilisés. Prenez également garde que j'ai supposé que les ID sont toujours des caractères «mot» (alphanumérique plus souligné) suivi d'un point, et n'ont pas d'espaces. Bien sûr, vous voudrez sauvegarder votre fichier avant de le modifier, et vous devriez tester le programme sur un fichier plus petit avant de mettre à jour le vrai.

use strict; 
use warnings; 

use Tie::File; 

my %ids; 
open my $fh, '<', 'newids.txt' or die $!; 
while (<$fh>) { 
    my ($old, $new) = split; 
    $ids{$old} = $new; 
} 

tie my @file, 'Tie::File', 'datafile.txt' or die $!; 
$file[0] =~ s<(\w+)(?=\.)><$ids{$1} // $1>eg; 
untie @file; 
Questions connexes