Как использовать значение в файле в качестве входных данных для расчета в awk - в bash? - PullRequest
0 голосов
/ 27 февраля 2020

Я пытаюсь рассчитать, если счетчик для каждой строки больше определенного значения, 30% от общего количества.

В течение цикла я получил процент в awk '$1=($1/100)*30' ${i}_counts > ${i}_percentage-value, и это одно число, вывод содержит только это.

Как сделать так, чтобы вычисление «значение было больше» для каждой строки ${i}_counts против ${i}_percentage-value? Другими словами, как использовать число внутри файла в качестве числового значения для математической операции?

Данные:

data.csv (извлечение)

SampleID    ASV    Count
1000A   ASV_1216    14
1000A   ASV_12580   150
1000A   ASV_12691   260
1000A   ASV_135     434
1000A   ASV_147     79
1000A   ASV_15      287
1000A   ASV_16      361
1000A   ASV_184     8
1000A   ASV_19      42

samples-ID-short

1000A
1000B
1000C

Таким образом, для каждого идентификатора выборки существует множество ASV, количество которых может сильно варьироваться, например, 50 ASV для 1000A, 120 для 1000B и так далее. У каждого ASV _ ## есть счетчик, и мой код предназначен для вычисления общей суммы счетчика, а затем выяснения, какое значение составляет 30% для каждого образца, сообщите, какой ASV _ ## больше 30%. В конечном итоге, он должен сообщить 0 для <30% и 1 для> 30%.

Вот мой код:

    for i in $(cat samplesID-short)
    do
    grep ${i} data.csv | cut -d , -f3 - > ${i}_count_sample
    grep ${i} data.csv | cut -d , -f2 - > ${i}_ASV
    awk '{ sum += $1; } END { print sum; }' ${i}_count_sample > ${i}_counts
    awk '$1=($1/100)*30' ${i}_counts > ${i}_percentage-value

#I was thinking about replicate the numeric value for the entire column and make the comparison "greater than", but the repetition times depend on the ASV counts for each sample, and they are always different.

    wc -l ${i}_ASV > n
    for (( c=1; c<=n; c++)) ; do echo ${i}_percentage-value ; done

    paste <(sed 's/^[[:blank:]]*//' ${i}_ASV) ${i}_count_sample ${i}_percentage-value > ${i}_tmp; 
    awk 'BEGIN{OFS="\t"}{if($2 >= $3) print $1}' ${i}_tmp > ${i}_is30;

#How the output should be:

    paste <(sed 's/^[[:blank:]]*//' ${i}_ASV) ${i}_count_sample ${i}_counts ${i}_percentage-value ${i}_is30 > ${i}_summary_nh
    echo -e "ASV_ID\tASV_in_sample\ttotal_ASVs_inSample\ttreshold_for_30%\tASV_over30%" | cat - ${i}_summary_nh > ${i}_summary
    rm ${i}_count_sample ${i}_counts ${i}_percentage-value ${i}_ASV ${i}_summary_nh ${i}_is30
    done &

Ответы [ 3 ]

2 голосов
/ 27 февраля 2020

Вы можете фильтровать по столбцу на основе значения, например,

$ awk '$3>300' data.csv
SampleID    ASV    Count
1000A   ASV_135     434
1000A   ASV_16      361

. Вы можете использовать> = больше или равно.

Похоже, ваш сценарий слишком усложняет ситуацию.

1 голос
/ 28 февраля 2020

это должно работать

$ awk 'NR==1 || $3>$1*3/10' file

SampleID    ASV    Count
1000A   ASV_135     434
1000A   ASV_16      361

или со столбцом индикатора

$ awk 'NR==1{print $0, "Ind"} NR>1{print $0, ($3>$1*3/10)}' file | column -t

SampleID  ASV        Count  Ind
1000A     ASV_1216   14     0
1000A     ASV_12580  150    0
1000A     ASV_12691  260    0
1000A     ASV_135    434    1
1000A     ASV_147    79     0
1000A     ASV_15     287    0
1000A     ASV_16     361    1
1000A     ASV_184    8      0
1000A     ASV_19     42     0
0 голосов
/ 28 февраля 2020

Не могли бы вы попробовать следующее:

awk -v OFS="\t" '
    NR==FNR {   # this block is executed in the 1st pass only
        if (FNR > 1) sum[$1] += $3
                # accumulate the "count" for each "SampleID"
        next
    }
                # the following block is executed in the 2nd pass only
    FNR > 1 {   # skip the header line
        if ($1 != prev_id) {
                # SampleID has changed. then update the output filename and print the header line
            if (outfile) close(outfile)
                # close previous outfile
            outfile = $1 "_summary"
            print "ASV_ID", "ASV_in_sample", "total_ASVs_inSample", "treshold_for_30%", "ASV_over30%" >> outfile
            prev_id = $1
        }
        mark = ($3 > sum[$1] * 0.3) ? 1 : 0
                # set the mark to "1" if the "Count" exceeds 30% of sum
        print $2, $3, sum[$1], sum[$1] * 0.3, mark >> outfile
                # append the line to the summary file
    }
' data.csv data.csv

data.csv:

SampleID    ASV    Count
1000A   ASV_1216    14
1000A   ASV_12580   150
1000A   ASV_12691   260
1000A   ASV_135     434
1000A   ASV_147     79
1000A   ASV_15      287
1000A   ASV_16      361
1000A   ASV_184     8
1000A   ASV_19      42
1000B   ASV_1       90
1000B   ASV_2       90
1000B   ASV_3       20
1000C   ASV_4       100
1000C   ASV_5       10
1000C   ASV_6       10

В следующих выходных примерах последнее поле ASV_over30% указывает 1, если число превышает 30% от суммы суммы.

1000A_summary:

ASV_ID  ASV_in_sample   total_ASVs_inSample     treshold_for_30%        ASV_over30%
ASV_1216        14      1635    490.5   0
ASV_12580       150     1635    490.5   0
ASV_12691       260     1635    490.5   0
ASV_135 434     1635    490.5   0
ASV_147 79      1635    490.5   0
ASV_15  287     1635    490.5   0
ASV_16  361     1635    490.5   0
ASV_184 8       1635    490.5   0
ASV_19  42      1635    490.5   0

1000B_summary:

ASV_ID  ASV_in_sample   total_ASVs_inSample     treshold_for_30%        ASV_over30%
ASV_1   90      200     60      1
ASV_2   90      200     60      1
ASV_3   20      200     60      0

1000C_summary:

ASV_ID  ASV_in_sample   total_ASVs_inSample     treshold_for_30%        ASV_over30%
ASV_4   100     120     36      1
ASV_5   10      120     36      0
ASV_6   10      120     36      0

[Пояснения]

При расчете среднего значения входных данных нам нужно go до конца данных. Если мы хотим распечатать входную запись и среднее значение (или другую информацию, основанную на среднем) одновременно, нам нужно использовать хитрость:

  • Чтобы сохранить все входные записи в память.
  • Чтобы прочитать входные данные дважды.

Поскольку awk подходит для чтения нескольких файлов, меняя порядок действий в зависимости от порядка файлов, я выбрал 2-й метод.

  • Условие NR==FNR возвращает TRUE при чтении только 1-го файла. Мы вычисляем сумму поля count в этом блоке как 1-й проход.
  • В операторе next в конце блока пропускаются следующие коды.
  • Если 1-й файл Готово, скрипт читает 2-й файл, который, естественно, совпадает с 1-м файлом.
  • При чтении 2-го файла условие NR==FNR больше не возвращает TRUE и 1-й блок пропускается.
  • 2-й блок снова считывает входной файл, открывая файл для печати вывода, построчно считывая входные данные и добавляя информацию, такую ​​как среднее значение, полученное в 1-м проходе.
...