Как добавить колонку в процентах - PullRequest
10 голосов
/ 29 ноября 2011

Я хотел бы рассчитать процент значения в каждой строке из всех строк и добавить его в качестве другого столбца. Ввод (разделитель \ t):

1   10      
2   10
3   20
4   40

Требуемый вывод с добавленным третьим столбцом, показывающим рассчитанный процент на основе значений во втором столбце:

1   10   12.50   
2   10   12.50
3   20   25.00
4   40   50.00

Я пытался сделать это сам, но когда я рассчитал общее количество для всех строк, я не знал, как сохранить остаток строки без изменений. Большое спасибо за помощь!

Ответы [ 4 ]

12 голосов
/ 29 ноября 2011

Вот, пожалуйста, один проход шаг awk решение -

awk 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file

[jaypal:~/Temp] cat file
1   10      
2   10
3   20
4   40
[jaypal:~/Temp] awk 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file
1 10 12.5
2 10 12.5
3 20 25
4 40 50

Обновление: Если при выводе требуется табуляция, просто установите переменную OFS в "\ t".

[jaypal:~/Temp] awk -v OFS="\t" 'NR==FNR{a = a + $2;next} {c = ($2/a)*100;print $1,$2,c }' file file
1   10  12.5
2   10  12.5
3   20  25
4   40  50

Прорыв операторов типа {действие}:

  • Первый шаблон NR==FNR. FNR - встроенная переменная awk, которая отслеживает количество записей (по умолчанию разделенных новой строкой) в данном файле. Таким образом, FNR в нашем случае будет 4. NR похож на FNR, но не сбрасывается до 0. Он продолжает расти. Таким образом, NR в нашем случае будет 8.

  • Этот шаблон будет верен только для первых 4 записей, и это именно то, что мы хотим. Изучив 4 записи, мы присваиваем сумму переменной a. Обратите внимание, что мы не инициализировали его. В awk нам не нужно. Однако это сломало бы, если весь столбец 2 равен 0. Таким образом, вы можете справиться с этим, поместив оператор if во второй оператор действия, т. Е. Выполнить деление, только если a> 0 еще скажет деление на 0 или что-то еще.

  • next необходим, потому что мы не хотим, чтобы выполнялся второй оператор pattern {action}. next говорит awk прекратить дальнейшие действия и перейти к следующей записи.

  • Как только четыре записи проанализированы, начинается следующий шаблон {действие}, который довольно прост. Делаем проценты и печатаем колонки 1 и 2 вместе с процентами рядом с ними.

Примечание: Как упомянуто в комментарии @lhf, эта однострочная строка будет работать, только если у вас есть набор данных в файле. Это не будет работать, если вы передадите данные по каналу.

В комментариях идет обсуждение способов заставить awk one-liner принимать данные от pipe вместо file. Ну, единственный способ, которым я мог придумать, это сохранить значения столбцов в array и затем использовать for loop, чтобы выплевывать каждое значение вместе с их процентом.

Теперь arrays в awk равны associative и никогда не в порядке, т. Е. Извлечение значений из массивов будет не в том порядке, в котором они вошли. Так что если все в порядке, то следующий лайнер должен работать.

[jaypal:~/Temp] cat file
1   10      
2   10
3   20
4   40

[jaypal:~/Temp] cat file | awk '{b[$1]=$2;sum=sum+$2} END{for (i in b) print i,b[i],(b[i]/sum)*100}'
2 10 12.5
3 20 25
4 40 50
1 10 12.5

Чтобы привести их в порядок, вы можете передать результат в sort.

[jaypal:~/Temp] cat file | awk '{b[$1]=$2;sum=sum+$2} END{for (i in b) print i,b[i],(b[i]/sum)*100}' | sort -n
1 10 12.5
2 10 12.5
3 20 25
4 40 50
2 голосов
/ 29 ноября 2011

Вы можете сделать это за пару проходов

#!/bin/bash

total=$(awk '{total=total+$2}END{print total}' file)
awk -v total=$total '{ printf ("%s\t%s\t%.2f\n", $1, $2, ($2/total)*100)}' file
1 голос
/ 29 ноября 2011

Вы должны выйти из него как %%.Например:

printf("%s\t%s\t%s%%\n", $1, $2, $3)
0 голосов
/ 29 ноября 2011

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

Содержание 'infile':

1       10 
2       10
3       20
4       40

Содержимое файла «script.awk»:

BEGIN {
        ## Tab as field separator.
        FS = "\t";
}

## First pass of input file. Get total from second field.
ARGIND == 1 {
        total += $2;
        next;
}

## Second pass of input file. Print each original line and percentage as third field.
{
        printf( "%s\t%2.2f\n", $0, $2 * 100 / total );
}

Запустите скрипт в моем окне linux:

gawk -f script.awk infile infile

И результат:

1       10      12.50
2       10      12.50
3       20      25.00
4       40      50.00
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...