Duplique um arquivo várias vezes, grave em arquivos duplicados, ordene os arquivos, conte a posição de linhas específicas após a ordenação

2

Antes de entrar em mais detalhes, quero salientar que já fiz uma parte da pergunta - > Você pode encontrá-lo aqui . Recebi algumas respostas legais, mas preciso fazer mais, então vou repetir minha pergunta e adicionar mais detalhes desta vez:

Portanto, eu tenho um arquivo com conteúdo exclusivo que se parece com isso (vamos chamar isso de myUniqueFile ):

chromosoom  start    end       phylop   GPS
chr1    28745756    28745756    7.905   5   
chr1    31227215    31227215    10.263  5
chr1    47562402    47562402    2.322   4
chr1    64859630    64859630    1.714   3
chr1    70805699    70805699    1.913   2
chr1    89760653    89760653    -0.1    0
chr1    95630169    95630169    -1.651  -1

Estes são locais diferentes com pontuações diferentes, como você pode ver.

E eu tenho outro arquivo que se parece com isso (vamos chamar isso de myDuplicationFile :

chromosoom  start    end       phylop   GPS
chr3    15540407    15540407    -1.391  -1
chr3    30648039    30648039    2.214   3
chr3    31663820    31663820    0.713   3
chr3    33093371    33093371    3.753   4
chr3    37050398    37050398    1.650   2
chr3    38053456    38053456    1.1     1
chr3    39597927    39597927    8.721   5

Então, para começar, gostaria de adicionar linhas (exceto o cabeçalho) de myUniqueFile a myDuplicationFile , mas quero que elas sejam adicionadas de forma que myDublicationFile seja duplicado para cada nova linha adicionada a partir de %código%. Então, myUniqueFile mantém seu conteúdo padrão + 1 nova linha adicionada de myDublicationFile . deve ser algo como isto:

myDublicatedFile1.txt:

chromosoom  start    end       phylop   GPS
chr3    15540407    15540407    -1.391  -1
chr3    30648039    30648039    2.214   3
chr3    31663820    31663820    0.713   3
chr3    33093371    33093371    3.753   4
chr3    37050398    37050398    1.650   2
chr3    38053456    38053456    1.1     1
chr3    39597927    39597927    8.721   5
chr1    28745756    28745756    0.905   1    <- first line from 'myUniquefile'


myDublicatedFile2.txt:

chromosoom  start    end       phylop   GPS
chr3    15540407    15540407    -1.391  -1
chr3    30648039    30648039    2.214   3
chr3    31663820    31663820    0.713   3
chr3    33093371    33093371    3.753   4
chr3    37050398    37050398    1.650   2
chr3    38053456    38053456    1.1     1
chr3    39597927    39597927    8.721   5
chr1    31227215    31227215    10.263  5    <- second line from 'myUniquefile'

então para cada nova linha adicionada um novo arquivo é criado como myUniqueFile etc ..

Depois que eu tiver esses myDublicatedFile3,4,5 com o novo conteúdo adicionado, eu gostaria de classificar esses arquivos para colunas específicas de alto a baixo, (para a coluna phylop ) eu faço isso com myDublicatedFiles , então é algo como isto:

myDublicatedFile1.method1.txt:

chr3    39597927    39597927    8.721   5
chr1    28745756    28745756    7.905   5 <- count 2
chr3    33093371    33093371    3.753   4
chr3    30648039    30648039    2.214   3
chr3    37050398    37050398    1.650   2
chr3    38053456    38053456    1.1     1
chr3    31663820    31663820    0.713   3
chr3    15540407    15540407    -1.391  -1
chromosoom  start    end       phylop   GPS

Então, depois de classificar esses arquivos, gostaria de saber a posição das linhas que adicionei após a classificação. Parece lógico para mim fazer algo com "grep" e usar uma "contagem".

Então, para for f in myDublicatedFile* ; do sort -g -r -k 3 $f >> $f.method1.txt é essa contagem / classificação 2, pois a linha adicionada de myDublicatedFile1.method1.txt acabou em segundo lugar no arquivo.

Depois de calcular a contagem / classificação para a coluna myUniquefile (method1) , gostaria de fazer uma classificação para a coluna phlop (method2) e calcular as fileiras das linhas adicionadas novamente. myDublicatedFile1.method1.method2.txt deve ser algo como isto:

chr3    39597927    39597927    8.721   5
chr1    28745756    28745756    7.905   5 
chr3    33093371    33093371    3.753   4
chr3    30648039    30648039    2.214   3
chr3    31663820    31663820    0.713   3
chr3    37050398    37050398    1.650   2
chr3    38053456    38053456    1.1     1
chr3    15540407    15540407    -1.391  -1
chromosoom  start    end       phylop   GPS

É fácil se as contagens / classificações forem escritas em arquivo diferente, para que eu possa usá-las posteriormente para as estatísticas. Então, os arquivos mais importantes são estes, pois eu vou acabar usando estes:)

Algo como:

countsForMethod1.txt:

29
3
5
6
50
etc.

countsForMethod2.txt:

7
3
21
45
etc..

Eu sei o código básico do terminal / bash para poder seguir a maior parte do código. É um monte de perguntas, mas eu fiz o meu melhor para ser o mais específico possível, espero que haja algumas pessoas legais que possam me ajudar com essas perguntas.

Agradeço a todos!

    
por Osman Altun 27.12.2017 / 15:06

4 respostas

3

Supondo que você tenha a versão de split do GNU coreutils e um shell como bash , ksh ou zsh esteja disponível (para o recurso de substituição de processo que está sendo usado aqui), você pode modificar o resposta aceite anterior para lidar com as linhas de cabeçalho e classificação, por exemplo,

tail -n +2 myUniqueFile | SHELL=$(command -v bash) split -l1 --filter='{ 
  head -n 1 myDuplicationFile &&
    sort -g -r -k4,4 <(tail -n +2 myDuplicationFile) -
  } > "$FILE"'

Você poderia então usar um simples awk one-liner para encontrar as posições das entradas myUniqueFile nos arquivos de saída:

awk 'FNR==NR && NR>1 {a[$0]++; next} ($0 in a) {print FILENAME, FNR}' myUniqueFile xa?
xaa 3
xab 2
xac 4
xad 5
xae 5
xaf 8
xag 9

Enxague e repita para os outros métodos / ordens de classificação.

    
por 27.12.2017 / 16:12
3

Este script calcula as classificações sem criar arquivos temporários (quase um arquivo será criado - o sorted_file ). Além disso, ele classifica myDuplicationFile uma vez para cada método e depois usa mais.

#!/bin/bash

rank_determination() {
    # Sorts the "myDuplicationFile" one time
    # The "sorted_file" will be used further.
    ###
    tail -n +2 myDuplicationFile | sort -g -r -k "$1","$1" > sorted_file

    # gawk iterates through "myUniqueFile" line by line (except the first line).
    gawk -v field_number="$1" '
    NR != 1 {
        # Stores the needed value for the each line
        ###
        search_value=$field_number
        cnt=1

        # then, it checks the specified column in the "sorted_file"
        # line by line for the value, which is less than 
        # the "search_value" from the "myUniqueFile".
        ###
        while((getline < "sorted_file") > 0) {
            if($field_number < search_value)
                break
            cnt++
        }

        print cnt
        # closing is needed for reading the file from the beginning
        # each time. Else, "getline" will read line by line consistently.
        ###
        close("sorted_file")
    }' myUniqueFile
}

# I create a function, which takes
# the number argument, which means the column number:
# "4" for "phylop" column, "5" for the "GPS" column.
#
# The function creates output, which you can redirect
# to the needed file.
# Call this function multiple times with different arguments
# for the each needed column.
rank_determination 4 > method1.txt
rank_determination 5 > method2.txt

Resultado

tail -n +1 -- method*
==> method1.txt <==
2
1
3
4
4
7
8

==> method2.txt <==
2
2
3
5
6
7
8
    
por 04.01.2018 / 15:30
2

Concordo com o que @WeijunZhou disse em seu comentário, você não precisa fazer todos esses arquivos temporários para fazer isso.

O script perl a seguir calculará as contagens para a classificação do seu Método 1 (filiais) e Método 2 (GPS), em uma passagem pelos dois arquivos.

Funciona mantendo uma lista ordenada (array) dos valores de phylop e GPS do arquivo duplicado, e então (para cada linha do arquivo único) calculando onde o valor de phylop e GPS teria ordenado em seus respectivos arrays ordenados .

#!/usr/bin/perl

use strict;

# get uniqfile and dupefile names from cmd line, with defaults
my $uniqfile = shift || 'myUniqueFile';
my $dupefile = shift || 'myDuplicationFile';

# Read in the dupefile and keep the phylops and GPS values.
# This could take a LOT of memory if dupefile is huge.
# Most modern systems should have no difficulty coping with even
# a multi-gigabyte dupefile.
my @phylop=();
my @GPS=();

open(DUPE,"<",$dupefile) || die "couldn't open '$dupefile': $!\n";
while(<DUPE>) {
  chomp;
  next if (m/^chromosoom/);

  my($chr,$start,$end,$phylop,$GPS) = split;
  push @phylop, $phylop + 0; # add 0 to make sure we only ever store a number
  push @GPS, $GPS + 0;
};
close(DUPE);

# Sort the @phylop and @GPS arrays, numerically descending
@phylop = sort {$a <=> $b} @phylop;
@GPS = sort {$a <=> $b} @GPS;

print "Method1\tMethod2\n";

# Now find out where the phylop and GPS value from each line of uniqfile
# would have ended up if we had sorted it into dupefile
open(UNIQ,"<",$uniqfile) || die "couldn't open '$uniqfile': $!\n";
while (<UNIQ>) {
  next if (m/^chromosoom/);
  chomp;

  my $phylop_sort_line=1;
  my $GPS_sort_line=1;

  my($chr,$start,$end,$phylop,$GPS) = split;

  for my $i (0..@phylop-1) {
    $phylop_sort_line++ if ($phylop < $phylop[$i]);
    $GPS_sort_line++ if ($GPS < $GPS[$i]);
  };

  #printf "%i\t%i\t#%s\n", $phylop_sort_line, $GPS_sort_line, $_;
  printf "%i\t%i\n", $phylop_sort_line, $GPS_sort_line;  
};
close(UNIQ);

quando executado com base nos dados de amostra fornecidos acima, a saída é:

$ ./counts-for-methods.pl
Method1 Method2
2       1
1       1
3       2
4       3
4       5
7       7
8       7

O script ignora completamente a linha de cabeçalho em ambos os arquivos, portanto, esses números de linha podem ser desativados em um caso o seu algoritmo atual os conte.

Ele também pressupõe que os valores do arquivo exclusivo sempre serão classificados imediatamente antes de um valor idêntico no arquivo duplicado. Se isso não for o que você deseja, altere as comparações < no for my $i (0..@phylop) loop para <= .

Se você precisar dos valores do Método 1 e do Método 2 separadamente, poderá extraí-los facilmente com awk . Ou o script perl pode ser facilmente modificado para abrir dois arquivos de saída, um para cada método, e imprimir os respectivos valores para cada arquivo.

aqui está uma versão para lidar com 151 campos nas linhas de entrada. Eu não tenho esse arquivo de entrada, então eu testei com a versão '5 fields' que foi comentada no código. A saída foi a mesma que a versão acima.

#!/usr/bin/perl

use strict;

# get uniqfile and dupefile names from cmd line, with defaults
my $uniqfile = shift || 'myUniqueFile';
my $dupefile = shift || 'myDuplicationFile';

my @phylop=();
my @GPS=();

# Read in the dupefile and keep the phylops and GPS values.
# This could take a LOT of memory if dupefile is huge.
# Most modern systems should have no difficulty coping with even
# a multi-gigabyte dupefile.
open(DUPE,"<",$dupefile) || die "couldn't open '$dupefile': $!\n";
while(<DUPE>) {
  chomp;
  next if (m/^chromosoom/);

  my @fields = split;

# 151 fields version:
  push @phylop, $fields[42]+0;
  push @GPS, $fields[150]+0;

# 5 fields version:
#  push @phylop, $fields[3]+0;
#  push @GPS, $fields[4]+0;

};
close(DUPE);

# Sort the @phylop and @GPS arrays, numerically descending
@phylop = sort {$b <=> $a} @phylop;
@GPS = sort {$b <=> $a} @GPS;

print "Method1\tMethod2\n";

# Now find out where the phylop and GPS from each line of uniqfile
# would have ended up if we had sorted it into the dupefile
open(UNIQ,"<",$uniqfile) || die "couldn't open '$uniqfile': $!\n";
while (<UNIQ>) {
  next if (m/^chromosoom/);
  chomp;

  my $phylop_sort_line=1;
  my $GPS_sort_line=1;

  my @fields = split;

  for my $i (0..@phylop-1) {

# 151 fields version:
    $phylop_sort_line++ if ($fields[42] < $phylop[$i]);
    $GPS_sort_line++ if ($fields[150] < $GPS[$i]);

# 5 fields version:
#    $phylop_sort_line++ if ($fields[3] < $phylop[$i]);
#    $GPS_sort_line++ if ($fields[4] < $GPS[$i]);
  };

  #printf "%i\t%i\t#%s\n", $phylop_sort_line, $GPS_sort_line, $_;
  printf "%i\t%i\n", $phylop_sort_line, $GPS_sort_line;

};
close(UNIQ);
    
por 04.01.2018 / 14:06
1

Só para economizar alguma digitação, chamarei o myUniqueFile sample e myDuplicationFile standard .

#!/bin/bash                                                                     

(
while read line; do
  echo $line|cat standard -|tail -n +2|sort -g -r -k 4|awk '/^chr1/{print FNR}' >> countsForMethod1.txt
  echo $line|cat standard -|tail -n +2|sort -g -r -k 5|awk '/^chr1/{print FNR}' >> countsForMethod2.txt
done
) <(tail -n +2 sample)

Explicação : O loop while inteiro é envolvido por um par de parênteses para fazer com que bash o trate como um único comando. Esse comando usa o arquivo sample como entrada, com a linha de cabeçalho removida usando o comando tail . Em seguida, ele é consumido pelo comando read , uma linha por vez. Isso significa que dentro do loop, $line é uma linha do arquivo sample . A variável é ecoada e canalizada para cat para gerar os arquivos myDuplicated* , apenas que eles são gerados "on the fly" e nunca gravados no disco. As linhas de cabeçalho são descartadas pelo tail antes dos arquivos serem classificados. awk é então usado para descobrir em qual linha a amostra está.

Editar : Eu acho que o split tem suas vantagens, enquanto esta resposta elimina a necessidade de arquivos intermediários.

    
por 27.12.2017 / 15:41