Я пишу сценарий для анализа некоторых данных. У меня есть несколько подмножеств файлов, и я хотел бы считать строку из этих файлов и записать результат в файл 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. Существует ли способ избежать этих трех цикл и сделать все вместе? Извините за недоразумение Вы все получили прекрасные идеи!
Можно использовать этот сценарий 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
присоединенный на ,
.Принятие Вас хочет вывод как 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
снова?
Интересный вопрос. Хороший случай для применения 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
и так далее.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