Как я могу считать строки по-другому именованных файлов и записать результат в файл CSV?

Я пишу сценарий для анализа некоторых данных. У меня есть несколько подмножеств файлов, и я хотел бы считать строку из этих файлов и записать результат в файл CSV. Я попытаюсь сделать пример. У меня есть эти два подмножество файла:

sample1.ext  
sample1.ext2  
sample1.ext3

sample2.ext  
sample2.ext2  
sample2.ext3

Я хотел бы считать строки содержавшимися во всех файлах в *.ext, *.ext2 и *.ext3 и запишите результаты в файл CSV, который кажется этому:

count(sample1.ext), count(sample1.ext2), count(sample1.ext3)  
count(sample2.ext), count(sample2.ext2), count(sample2.ext3)

После включения первой серии файла *.ext, Я произвел результаты к первому столбцу файла CSV. Как я пишу вывод второй серии количества *.ext2 во второй столбец того же файла CSV? И то же для третьего столбца?


Благодарите всем для ответов, я пытался адаптировать их к своим файлам, но к сожалению я не могу сделать этого. Примером, который я отправил, был просто пример, куда я поместил числа вместо странных расширений, чтобы быть самым легким понять проблему. Вы все поняли, но Вы сфокусировались слишком много на числах, которые не существуют в действительности. Я объясню Вас снова использование реальных файлов. Эти файлы прибывают из отображения геномных данных к ссылочному геному. Я рассматриваю эти данные для очистки их, таким образом, у меня есть три шага, где количество строк изменяется. Так файл:

name.sort.bam  
name.mapped.bam  
name.rmdup.bam  
othername.sort.bam  
othername.mapped.bam  
othername.rmdup.bam   

Дополнительный обман является сжатым файлом. Для подсчета строк в этом файле существует специальная командная строка:

samtools view -c (file)

Единственным путем я нашел, должен был выполнить итерации в каждого *sort.bam, *mapped.bam, *rmdup.bam и запишите вывод txt для каждого и вставьте их в конце в файле CSV. Существует ли способ избежать этих трех цикл и сделать все вместе? Извините за недоразумение Вы все получили прекрасные идеи!

0
задан 14 February 2016 в 19:02

3 ответа

Можно использовать этот сценарий Perl:

#! /usr/bin/perl
use strict;
use warnings;

my @names;
my @files;

@ARGV == 1 || die();

opendir(my $dir, $ARGV[0]) || die $!;

while(readdir($dir)) {
    if($_ =~ /(.*)\.(sort|mapped|rmdup)\.bam$/) {
        grep(/^$1$/, @names) == 0 && push(@names, $1);
    }
}

close($dir);

foreach my $name (sort(@names)) {
    my @fields;
    push(@fields, $name);
    foreach my $extension ("sort", "mapped", "rmdup") {
        if(! -f "$ARGV[0]/$name.$extension.bam") {
            push(@fields, 0);
            print STDERR "'$ARGV[0]/$name.$extension.bam' missing\n";
            next;
        }
        my $count = `<"$ARGV[0]/$name.$extension.bam" wc -l`;
        chomp($count);
        push(@fields, $count)
    }
    print(join(", ", @fields)."\n")
}

Сохраните его где-нибудь в Вашей системе, сделайте его исполняемым файлом и выполните его передающий каталог как аргумент:

path/to/script path/to/directory
% tree directory
directory
├── name.mapped.bam
├── name.rmdup.bam
├── name.sort.bam
├── othername.mapped.bam
├── othername.rmdup.bam
└── othername.sort.bam

0 directories, 6 files
% perl script.pl directory
name, 0, 0, 0
othername, 0, 0, 0
% for f in directory/*.sort.bam; do printf 'line\n' >>"$f"; done
% perl script.pl directory                                      
name, 1, 0, 0
othername, 1, 0, 0

То, что делает сценарий:

  • Выполняет итерации через все файлы в path/to/directory; если имя файла соответствует .*\.(sort|mapped|rmdup)\.bam$, добавляет строку прежде .sort.bam, .mapped.bam или .rmdup.bam к списку @names если не уже в списке;
  • Для каждого имени в отсортированном @names список как $name, добавляет $name к списку @fields; для каждого расширения в sort, mapped и rmdup как $extension проверки, если $name.$extension.bam существует в path/to/directory; если файл не существует, добавляет 0 кому: @fields, печатает сообщение об ошибке и шаги к следующему $extension / $name; если файл существует, добавляет вывод <"$name.$extension.bam" wc -l кому: @fields; однажды все возможные значения для $extension были выполнены с помощью итераций, печатает строку, содержащую элементы @fields присоединенный на ,.
1
ответ дан 26 July 2019 в 08:17

Принятие Вас хочет вывод как 42, 19, 10207, 3 на каждой строке (никакие имена файлов), wcи некоторые Bashлуг решит Вашу проблему.

outfile="Result.csv" 
for samplenum in $( seq 1 100 ) ; do
    line=""
    for file in sample${samplenum}.* ; do
        numlines=$( wc -l <$file )
        line="$line $numlines,"
    done
    # remove the final comma
    line=${line%,}
    # not quoting $line below will suppress the initial blank 
    echo $line >> $outfile 
done

Читать man bash, man wc, man seq и man bash снова

Ответ на комментарий:

Вы читали man страницы?

$( seq 1 100) заменяется результатами seq 1 100 команда, которая просто производит целые числа от 1 до 100 (который чтение man seq сказал бы Вам). Замените его чем-то, что предоставляет числа образцов, которые Вы имеете.

Поместите код в файл (например. test.sh) и выполненный это с bash -x test.sh видеть детали. Замените seq 1 100 с seq 1 2 для теста, для предотвращения лавины вывода.

samplenum содержит количество образца, который, для этого примера, работает от 1 до 100.

sample, в sample${samplenum}.* просто строка. Это связывается со значением samplenum и строка .* произвести шаблон имени файла, например. sample1.* в первый раз через for samplenum ... цикл, sample2.* во второй раз, и т.д.

Вы читали и понимали, man bash, man wc, man seq и man bash снова?

1
ответ дан 26 July 2019 в 08:17

Опция Python

Интересный вопрос. Хороший случай для применения Python groupby()

Так как Ваши файлы находятся в единственном, "плоском" каталоге:

#!/usr/bin/env python3
from itertools import groupby
import os
import sys

dr = sys.argv[1]
# list the files in the directory, split into "sortable" elements
flist = [[item, item.split(".", 1)] for item in os.listdir(dr)]
# sort the file list by first section (until the first found dot)
flist.sort(key=lambda x: x[1][0])
# create sub groups of the files, grouped by first section of name
for key, line in groupby(flist, lambda x: x[1][0]):
    line = list(line)
    # sort the files by second section of name for correct order in the csv lines
    line.sort(key=lambda x: x[1][1])
    # count the lines of the files, arrange the csv file
    print((", ").join([str(len(open(dr+"/"+f[0]).readlines())) for f in line]))

Как это работает

Если каталог содержит девять файлов:

sample1.ext                  2 lines
sample1.ext2                 3 lines
sample1.ext3                 3 lines

sample2.ext                  1 lines
sample2.ext2                 1 lines
sample2.ext3                 4 lines

sample3.ext                  6 lines
sample3.ext2                 1 lines
sample3.ext3                 4 lines
  • Сценарий перечисляет файлы, разделяет каждое из имен в два раздела, например:

    sample2
    

    и

    ext2
    

    начиная с порядка и строк и длины файла в строках зависит от точной сортировки этих двух разделов.

  • Сценарий затем сортирует файлы по первому разделу имени, так как длина каждого из файлов (с подобным разделом имени) должна быть сгруппирована на первый раздел в одну строку; sample1, sample2, sample3 и так далее.
  • Впоследствии, sub группы (на csv строка), создаются, правильно сортируются по второму разделу имени, для создания (строка-), числа появляются в правильном порядке в строке

Результат:

python3 '/home/jacob/Bureaublad/create_csv.py' '/home/jacob/Bureaublad/samples' 
2, 3, 3
1, 1, 4
6, 1, 4

Как использовать

  • Скопируйте сценарий в пустой файл, сохраните его как create_csv.py
  • Выполните его с каталогом с Вашими файлами как аргумент

    python3 /path/to/create_csv.py /path/to/directory_with_files
    

Важное примечание

Метод, используемый для подсчета строк, является соответствующим, пока файлы не огромны. Если бы файлы, другой метод для подсчета строк привел бы к лучшей производительности.


Править

В результате последней информации, добавленной к Вашему вопросу, отредактированной версии сценария. По совпадению не много должно быть изменено: сценарий уже разделил имена файлов первой найденной точкой командой:

item.split(".", 1)

Так как последний раздел имени .bam, который равен на всех файлах, это бессмысленно для порядка сортировки.

Затем мы только должны заменить "старый" способ считать строки файла:

str(len(open(dr+"/"+f[0]).readlines()))

(реализация Python и интеграция в сценарий-) команда Вы обеспечили:

str(subprocess.check_output(["samtools", "view", "-c", dr+"/"+f[0]]).decode("utf-8").strip())

Отредактированный сценарий

#!/usr/bin/env python3
from itertools import groupby
import os
import sys
import subprocess

dr = sys.argv[1]
# list the files in the directory, split into "sortable" elements
flist = [[item, item.split(".", 1)] for item in os.listdir(dr)]
# sort the file list by first section (until the first found dot)
flist.sort(key=lambda x: x[1][0])
# create sub groups of the files, grouped by first section of name
for key, line in groupby(flist, lambda x: x[1][0]):
    line = list(line)
    # sort the files by second section of name for correct order in the csv lines
    line.sort(key=lambda x: x[1][1])
    # count the lines of the files, arrange the csv file
    print((", ").join([
        str(subprocess.check_output(["samtools", "view", "-c", dr+"/"+f[0]]).decode("utf-8").strip())
        for f in line]))

Примечание:

Обратите внимание, что порядок чисел в строке определяется отсортированным порядком второй части имени, например.

mapped.bam, rmdup.bam, sort.bam  
1
ответ дан 26 July 2019 в 08:17

Другие вопросы по тегам:

Похожие вопросы: