Операции с колонками в файле Linux Shell - PullRequest
1 голос
/ 19 марта 2012

У меня есть файл с записями, разделенными пустым пространством. Например:

example.txt

24676 256 218503341 2173
13236272 500 1023073758 5089
2230304 96 15622969 705
0 22 0 526
13277 28 379182 141

Я хотел бы вывести в командной строке результат «столбец 1 / столбец 3» или simila. Я верю, что это можно сделать с помощью awk. Однако некоторые записи равны 0, следовательно, деление на 0 дает:

фатально: попытка деления на ноль

В более сложном случае я хотел бы найти медианное значение (или некоторый процентиль) деления.

Ответы [ 2 ]

3 голосов
/ 19 марта 2012

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

awk '$3 != 0 { print $1/$3 }' your-data-file

awk '{ if ($3 != 0) print $1/$3 }' your-data-file

Вопрос изменился & mdash; вместо этого вывести 0 Ответ не намного сложнее:

awk '{ if ($3 != 0) print $1/$3; else print 0 }' your-data-file

Медианы и другие процентили гораздо сложнее иметь дело. Проще всего, если данные в отсортированном порядке. Намного проще, чем я ожидал бы использовать числовую сортировку и затем обработать данные оттуда.


Я выкопал старый сценарий оболочки, который вычисляет описательную статистику - мин, макс, режим, медиана и децили одного столбца данных:

:   "@(#)$Id: dstats.sh,v 1.2 1997/06/02 21:45:00 johnl Exp $"
#
#   Calculate Descriptive Statistics: min, max, median, mode, deciles

sort -n $* |
awk 'BEGIN { max = -999999999; min = 999999999; }
    {   # Accumulate basic data
        count[$1]++;
        item[++n] = $1;
        if ($1 > max) max = $1;
        if ($1 < min) min = $1;
    }
END {   # Print Descriptive Statistics
        printf("# Count = %d\n", n);
        printf("# Min = %d\n", min);
        decile = 1;
        for (decile = 10; decile < 100; decile += 10)
        {
            idx = int((decile * n) / 100) + 1;
            printf("# %d%% decile = %d\n", decile, item[idx]);
            if (decile == 50)
                median = item[idx];
        }
        printf("# Max = %d\n", max);

        printf("# Median = %d\n", median);
        for (i in count)
        {
            if (count[i] > count[mode])
                mode = i;
        }
        printf("# Mode = %d\n", mode);
    }'

Начальные значения min и max не совсем научные. Это служит иллюстрацией.

(Эта версия 1997 года практически идентична предшествующей версии 1991 года - фактически все, кроме строки информации о версии, идентичны. Итак, коду более 20 лет.)

2 голосов
/ 19 марта 2012

Вот одно из решений:

awk '
  $3 != 0 { vals[$NR]=$1/$3; sum += vals[$NR]; print vals[$NR] }
  $3 == 0 { vals[$NR]=0; print "skipping division by 0" }
  END { sort vals; print "Mean = " sum/$NR ", Median ~ " vals[$NR/2] }
  ' < your_file

Это вычислит, напечатает и накопит частное, если столбец 3 rd не равен нулю.Когда он достигает конца вашего файла (который должен , а не иметь пустую строку), он выведет среднее значение и медиану всех отношений, принимая 0 для каждой строки, в которой он будет делиться на ноль.

В awk, $n означает поле n th , начиная с 1, а $NR означает количество записей (то есть количество строк)которые были обработаны.Каждое частное хранится в массиве vals, что позволяет нам вычислить медианное значение.

В реальной жизни медиана определяется как «средний» элемент с нечетным числом элементов или средним значениемдва «средних» элемента имеют четное количество элементов.

И вы сами по себе, когда дело доходит до реализации функции sort!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...