Linux суммирует таблицу и суммирует все столбцы из каждого данного вхождения - PullRequest
0 голосов
/ 25 октября 2018

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

таблица

index,sampleA,sampleB,sampleC
nana,22,12,4
baba,47,4,5
nana,1,5,9
nana,7,5,8

после разбора

index,sampleA,sampleB,sampleC
nana,30,22,21
baba,47,4,5

Буду очень признателен, если вымог бы помочь мне в этом.Большое спасибо.

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Вы не указываете оболочку, но если вам нравится использовать ksh (93l +), это также должно помочь.

Этот скрипт делает некоторые предположения:

  1. Может быть любое количество столбцов, НО каждая строка имеет одинаковое количество столбцов
  2. В имени индекса нет пробела
  3. В каждом столбце всегда есть значение

    #!/bin/ksh
    
    # CSV to input as first argument, CSV to ouput as second argument
    InputCSV=$1
    OutputCSV=$2
    
    typeset -A Index
    
    while read line; do
        lineArray=(${line//,/ })
        # Assume that the first column is always named "index", but you can modify this
        if [[ ${lineArray[0]} == "index" ]]; then
            titleArray=(${line//,/ })
            continue
        fi
        for ((i=1;i<${#lineArray[*]};i++)); do
            if [[ -z ${Index[${lineArray[0]}][${titleArray[$i]}]} ]]; then
                    Index[${lineArray[0]}]+=( [${titleArray[$i]}]=${lineArray[$i]} )
            else
                    Index[${lineArray[0]}][${titleArray[$i]}]=$(( ${Index[${lineArray[0]}][${titleArray[$i]}]} + ${lineArray[$i]} ))
            fi
        done
    done < $InputCSV
    
    exec 3>$OutputCSV
    
    titleBar=${titleArray[0]}
    for ((i=1;i<${#titleArray[*]};i++)); do
        titleBar+=",${titleArray[$i]}"
    done
    
    print $titleBar >&3
    
    for j in ${!Index[@]}; do
        outLine=$j
        for ((i=1;i<${#titleArray[*]};i++)); do
                outLine+=",${Index[$j][${titleArray[$i]}]}"
        done
        print $outLine >&3
    done
    
    exec 3>&-
    
0 голосов
/ 25 октября 2018

Немного затянуто, но что-то вроде этого сделает работу:

awk -F"," 'BEGIN{OFS=FS} NR==1{print $0; next} NR>1{sampleA[$1]+=$2; sampleB[$1]+=$3; sampleC[$1]+=$4}END{for (sample in sampleA){print sample, sampleA[sample], sampleB[sample], sampleC[sample]}}' yourfile

Объяснение:

  1. Разделите каждую строку запятой -F","
  2. Перед обработкой файла убедитесь, что разделитель выходных полей соответствует разделителю полей (запятая) BEGIN{OFS=FS}
  3. Если это первая строка файла, распечатайте его (это заголовок) и затем продолжитена следующую строку NR==1{print $0; next}
  4. Если это не строка заголовка, создайте три массива для хранения совокупных значений из столбцов 2, 3, 4. «Ключ» массивов - это значение в столбце1 NR>1{sampleA[$1]+=$2; sampleB[$1]+=$3; sampleC[$1]+=$4}
  5. Наконец, в конце выполните цикл по первому из трех массивов (все они будут одинаковой длины, поэтому нам нужно только один цикл).Затем распечатайте значения, сохраненные в каждом для этого ключа: END{for (sample in sampleA){print sample, sampleA[sample], sampleB[sample], sampleC[sample]}}
...