Используя указанные c столбцы, выведите строки, которые присутствуют 3 раза в текстовом файле. - PullRequest
0 голосов
/ 27 мая 2020

У меня есть текстовый файл, и я хочу вывести строки, в которых первые 4 столбца появляются в файле ровно три раза.

chr1    1   A   T   sample1
chr1    3   G   C   sample1
chr2    1   G   C   sample1
chr2    2   T   A   sample1
chr3    4   T   A   sample1
chr1    1   A   T   sample2
chr2    3   T   A   sample2
chr3    4   T   A   sample2
chr1    1   A   T   sample3
chr2    1   G   C   sample3
chr3    4   T   A   sample3
chr1    1   A   T   sample4
chr2    1   G   C   sample4
chr5    1   A   T   sample4
chr5    2   G   C   sample4

Если строка появляется три раза, я хочу добавить два столбца для двух других выборок, в которых она появляется, чтобы вывод сверху выглядел так:

chr2    1   G   C   sample1 sample3 sample4
chr3    4   T   A   sample1 sample2 sample3

I сделал бы это в R, но файл слишком велик для чтения, поэтому я ищу решение, которое будет работать в linux. Я искал awk, но не могу найти ничего для этой конкретной ситуации.

Файл в настоящее время не отсортирован.

Заранее спасибо!

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

Ответы [ 3 ]

3 голосов
/ 27 мая 2020

Использование GNU datamash, tr и awk при условии, что ввод и вывод разделены табуляцией:

$ datamash -s -g1,2,3,4 collapse 5 < file | tr ',' '\t' | awk 'NF==7'
chr3    4       T       A       sample1 sample2 sample3

Сначала используйте datamash для сортировки входного файла, сгруппируйте по первые четыре поля и сверните значения (через запятую) в 5-м поле. Результат будет выглядеть так:

$ datamash -s -g1,2,3,4  collapse 5 < file
chr1    1       A       T       sample1,sample2,sample3,sample4
chr1    3       G       C       sample1
chr2    1       G       C       sample1
chr2    2       G       C       sample3,sample4
chr2    2       T       A       sample1
chr2    3       T       A       sample2
chr3    4       T       A       sample1,sample2,sample3
chr5    1       A       T       sample4
chr5    2       G       C       sample4

Затем направьте вывод в tr, чтобы преобразовать запятые в табуляции, и, наконец, используйте awk для печати строк с семью полями.


Использование awk:

awk '
  BEGIN{ FS=OFS="\t" }
  {
    idx=$1 FS $2 FS $3 FS $4
    cnt[idx]++
    data[idx]=(cnt[idx]==1 ? "" : data[idx] OFS) $5
  }
  END{
    for (i in cnt)
      if (cnt[i]==3) print i, data[i]
  }
' file

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

В конечном блоке l oop поверх массива cnt и вывести индекс и значение массива data, если количество равно трем.

3 голосов
/ 27 мая 2020

Для удовольствия, решение с использованием (заключено в сценарий оболочки, который принимает файл данных в качестве единственного аргумента)

#!/bin/sh

file="$1"

# Consider loading your data into a persistent db if doing a lot of work
# on it, instead of a temporary one like this.
sqlite3 -batch -noheader <<EOF
.mode tabs
CREATE TEMP TABLE data(c1, c2 INTEGER, c3, c4, c5);
.import "$file" data
-- Not worth making an index for a one-off run, but for
-- repeated use would come in handy.
-- CREATE INDEX data_idx ON data(c1, c2, c3, c4);
SELECT c1, c2, c3, c4, group_concat(c5, char(9)/*tab*/)
FROM data
GROUP BY c1, c2, c3, c4
HAVING count(*) = 3
ORDER BY c1, c2, c3, c4;
EOF

Затем:

$ ./demo.sh input.tsv
chr3    4   T   A   sample1 sample2 sample3

Это единственный экземпляр в ваших выборочных данных, где их ровно 3.

2 голосов
/ 27 мая 2020

Это может быть то, что вы ищете:

$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ curr = $1 FS $2 FS $3 FS $4 }
curr != prev {
    prt()
    cnt = samples = ""
    prev = curr
}
{ samples = (cnt++ ? samples " " : "") $5 }
END { prt() }
function prt() { if ( cnt == 3 ) print prev samples }

.

$ sort -k1,4 file | awk -f tst.awk
chr2    1   G   C   sample1 sample3 sample4
chr3    4   T   A   sample1 sample2 sample3

sort использует пейджинг et c. для обработки ввода, который слишком велик для размещения в памяти, поэтому он будет успешно обрабатывать ввод большего размера, чем могут обрабатывать другие инструменты, а сценарий awk почти ничего не сохраняет в памяти.

...