Извлечь последовательность в определенных позициях с помощью файла позиций и целевого файла

У меня есть файл последовательности ДНК1 (250 млн символов/байт), который выглядит так (формат FASTA):

$sequence-file1
TCCTCCAAATGATGTCAGTGTCCTCCATATGATGTCAATGTCCTCCATAT
GATGTCAATATCCTCCGTATGATGTCAATATCCTCCGTATGATGTCAATA
TCCTCCATATGATGTCAGTGTCCTCTGTATGACATCAATATCCTCCATAC
GATGCCCCTGTCCTTCATATGATGTCAGTGTCCTTTTGTGAGCACCAGTG
TCCTTTGTATGACATCAGTAGTCTCCCATGAATGTCACTGTCTTCCCATA

и последовательность position-file2 в этом формате с непоследовательными позициями:

$positions-file2
1
2
7
39
51

Мне нужно извлечь символы из файла последовательности1 в позиции, указанные в файле позиций2, и распечатать «символ позиции». Следующая программа awk:

$prog.file.awk    
    {
        for (i=1;i<=length;i++) 
            if((i+(NR-1)*length)==x) 
                print x"\t"substr($0,i,1);exit 
    }

... делает это только для первых 50 строк, когда я передаю ему позиции для «x» через xargs: xargs -I{i} awk -v x={i} -f prog.file.awk sequence-file1 < positions-file2 Вывод:

1   T
2   C
7   A
39  T

Любое число выше 50 в position-file2 игнорируется. Мой желаемый результат с учетом вышеуказанных входных файлов:

1   T
2   C
7   A
39  T
51  G

Также я ищу экономичное решение, потому что для 250-мегабайтного символьного файла у меня есть около 200 миллионов позиций для сопоставления.


person isosceleswheel    schedule 07.06.2014    source источник
comment
Хм? Что означает файл 39 в последовательностях position2? Напечатайте 39-е, что на какой строке? Тогда вы говорите, что вам нужно сравнивать файлы - сравнивать какие файлы с какими и что определять? Почему вы говорите, что файл имеет пробелы?   -  person Mark Setchell    schedule 07.06.2014
comment
Привет, Марк, я сделал небольшое редактирование относительно пробелов (непоследовательных позиций). Числа в position-file2 относятся к номеру символа в sequence-file1. Таким образом, 39 будет относиться к 39-му символу в файле1, 1 — к первому символу, 100 — к 100-му...   -  person isosceleswheel    schedule 07.06.2014
comment
Если вы выводите 5 строк для каждой строки вашего входного файла, обязательно должно быть 25 строк вывода?   -  person Mark Setchell    schedule 07.06.2014
comment
Я не вывожу 5 строк для каждой строки входного файла...   -  person isosceleswheel    schedule 07.06.2014
comment
Если вы напечатаете позицию 1,2,7,39,51 каждой строки, вы наверняка получите 5 строк для каждой строки входного файла?   -  person Mark Setchell    schedule 07.06.2014
comment
Как вы можете напечатать позицию 51, когда в строке всего 50 символов?   -  person Mark Setchell    schedule 07.06.2014
comment
Ну, я пытался прийти к позиции 51, выполнив вычисления (NR-1)*length+i   -  person isosceleswheel    schedule 07.06.2014


Ответы (2)


Следующее будет работать, когда вы исправите свои данные:

awk 'FNR==NR{p[$1]++;next} {for(x in p)print x,substr($0,x,1)}' pf2 sf1

На данный момент в каждой строке всего 50 символов, поэтому вы не можете напечатать 51-й. Он также не просматривает каждый символ в строке, а просто извлекает те, которые вы укажете, так что это будет намного быстрее.

Пояснение

FNR==NR означает, что все, что указано в фигурных скобках, относится только к обработке файла pf2. Там я сохраняю позиции в массиве p[], поэтому после чтения файла позиций p[1]=1, p[2]=1, p[7]=1, p[39]=1 и p[51 ]=1.

Код во втором наборе фигурных скобок применяется только ко второму файлу, sf1. Он перебирает все позиции, которые мы сохранили в p[], и печатает выбранные символы из текущей записи, извлекая их с помощью substr().

person Mark Setchell    schedule 07.06.2014
comment
Я пробую это с файлом последовательности, переформатированным в одну строку символов 250M. Я пытался просто сделать xargs -I{i} <positions с этим форматом и командой awk print x,substr($0,x,1), но это было очень медленно. - person isosceleswheel; 07.06.2014
comment
Я не масштабировался для проблемы, которая у меня была. Я выбрал решение, которое включало переформатирование больших файлов в отдельные столбцы, а затем сопоставление файлов столбцов. - person isosceleswheel; 18.06.2014

Я знаю, что тег говорит awk, но awk кажется неправильным инструментом для работы, учитывая ожидаемый размер наборов данных. Мой C оказался немного длиннее, чем ожидалось, но частично, потому что я добавил код для проверки завершения строки и длины строки.

[dennis@localhost dna]$ gcc -Wall reindex.c 
[dennis@localhost dna]$ ./a.out sequence.dat position.dat
1   T
2   C
7   A
39  T
51  G

Кажется, сработало после того, как я скопировал текст вашего примера sequence-file1 в sequence.dat и position-file2 в position.dat.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>


void usage(int argc,char **argv);
int analyze(
  FILE *fp 
  ,long *pLineTextLen   /**< OUT: Length of alpha text per line      */
  ,long *pLineBinLen    /**< OUT: Total length of line including lf  */
  );

int reindex(
  FILE *seqFp           /**< IN: file with sequence to reindex       */
  ,FILE *posFp          /**< IN: file with indexes to extract        */
  ,long lineTextLen     /**< IN: text to index per line              */
  ,long lineBinLen      /**< IN: characters including termintion     */
  );


int main( int argc, char **argv)
{
  int errval;
  FILE * seqFp=NULL;
  FILE * posFp=NULL;
  long   lineTextLen;
  long   lineBinLen;
  char  *sequenceName=NULL;
  int    argIdx;

  argIdx=1;

  if(argIdx >= argc)
  {
    usage(argc,argv);
    errval=-__LINE__;
    goto exiterror;
  }
  seqFp = fopen(argv[argIdx],"r");
  if(seqFp == NULL)
  {
    errval=errno;
    fprintf(stderr,"Unable to open %s\n",argv[argIdx]);
    goto exiterror;
  }
  sequenceName = argv[argIdx];
  argIdx++;
  if(argIdx >= argc)
  {
    usage(argc,argv);
    errval=-__LINE__;
    goto exiterror;
  }
  posFp = fopen(argv[argIdx],"r");
  if(posFp == NULL)
  {
    errval=errno;
    fprintf(stderr,"Unable to open %s\n",argv[argIdx]);
    goto exiterror;
  } 
  errval = analyze(seqFp,&lineTextLen,&lineBinLen);
  if(errval)
  {
    fprintf(stderr,"Unable to estimate line length of %s\n"
            ,sequenceName);
    errval=-__LINE__;
    goto exiterror;
  }
  errval = reindex(seqFp,posFp,lineTextLen,lineBinLen);
  if(errval)
  {
    fprintf(stderr,"Unable to reindex (errval=%i)\n"
            ,errval);
    goto exiterror;
  }


exiterror:
  if(seqFp != NULL)
  {
    fclose(seqFp);
    seqFp=NULL;
  }
  if(posFp != NULL)
  {
    fclose(posFp);
    posFp=NULL;
  }
  return(errval);

}


void usage(int argc,char **argv)
{
  (void)argc;  /* yes I'm ignoring it atm */

  fprintf(stderr,"%s {seqeuence-file} {position-file}\n"
          ,argv[0]);
  return;
}

/*********************************************************************/
/** Analyze file to determine line lenth
 * 
 * Analyze first few lines of file for identical length text
 * lines consisting only of alpha text.
 * 
 * return non-zero if lines not consistent or other error.
 *********************************************************************/
int analyze(
  FILE *fp 
  ,long *pLineTextLen   /**< OUT: Length of alpha text per line      */
  ,long *pLineBinLen    /**< OUT: Total length of line including lf  */
  )
{
  int input;
  int lineTextLen=0;
  int lineBinLen=0;
  int confirmCount=0;
  int count=0;
  enum
  {
    TEXT_READ=0,
    TERM_READ=1
  }
  state= TEXT_READ;

  do
  {
    input=fgetc(fp);
    if(input != EOF)
    {
      if(isalpha(input))
      {
        if( state == TERM_READ)
        {
          state = TEXT_READ;
          if(lineBinLen != 0 )
          {
            if( count != lineBinLen )
            {
              /* mismatch */
              goto exiterror;
            }
            confirmCount++;
          }else
          {
            lineBinLen=count;
          }
          count=0;  /* start new line */
        }
        count++;
      }
      else if( ( input == '\r' )
               || (input == '\n')
               || isblank(input) )
      {
        if(state == TEXT_READ)
        {
          state = TERM_READ;
          if(lineTextLen!=0)
          {
            if(lineTextLen  != count )
            {
              /* mismatch */
              goto exiterror;
            }
            confirmCount++;
          }
          else
          {
            lineTextLen=count;           
          }
        }
        count++;
      }
    }
  }
  while(input!=EOF 
        && confirmCount<4); /* 2 text and 2 bin */
exiterror:  
  rewind(fp);
  if( pLineTextLen )
  {
    *pLineTextLen = lineTextLen;
  }
  if( pLineBinLen )
  {
    *pLineBinLen = lineBinLen;
  }

  return(confirmCount<4);  /* non-zero if not confirmed */
}

/**********************************************************************/
/** reindex sequence file to std out.
 * 
 * Print char at specified character indexes in sequence file.
 * Character indexes are one-based index of characters in 
 * seq file not including line terminations.  Line length and 
 * termination are assumed to be consistent and specified by 
 * passed parameters.
 *
 * Indexes are read as text strings one per line from pos file.
 *
 * /return non-zero on error. 
 *********************************************************************/

int reindex(
  FILE *seqFp           /**< IN: file with sequence to reindex       */
  ,FILE *posFp          /**< IN: file with indexes to extract        */
  ,long lineTextLen     /**< IN: text to index per line              */
  ,long lineBinLen      /**< IN: characters including termintion     */
  )
{
  int  errval=0;
  char buffer[80];
  char *pInput=NULL;
  long  index;
  long  lines;
  long  seekPos;
  int   sequence;

  do
  {
    pInput=fgets(buffer,sizeof(buffer),posFp);
    if( (pInput != NULL)
        && ( !isalnum(pInput[0]) ))  /* empty line */
    {
      pInput=NULL;
    }

    if(pInput != NULL)
    {
      index=strtol(pInput,NULL,0);
      if(index==0)
      {
        errval=-__LINE__;
        goto exiterror;
      }
      index--;  /* switch to zero based index */
      /* integer truncated division expected below */
      lines=index/lineTextLen;
      seekPos= ( ( lines * lineBinLen ) 
                 + ( index - lines * lineTextLen ) );

      fseek(seqFp,seekPos,SEEK_SET);
      sequence=fgetc(seqFp);
      if(sequence == EOF)
      {
        errval=-__LINE__;
        goto exiterror;
      }
      fprintf(stdout,"%li\t%c\n"
              ,index+1 /* convert back to one based */
              ,sequence);
    }

  }while(pInput!=NULL);

exiterror:
  return(errval);

}
person dennis    schedule 07.06.2014