【问题标题】:Column Operations in file Linux Shell文件 Linux Shell 中的列操作
【发布时间】:2012-03-19 11:00:32
【问题描述】:

我有一个文件,其中的条目由空格分隔。例如:

example.txt

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

我想在命令行中打印“第 1 列/第 3 列”或类似的结果。我相信它可以用awk来完成。但是,有些条目是 0,因此除以 0 给出:

致命:尝试除以零

在更高级的情况下,我想找到除法的中值(或某个百分位数)。

【问题讨论】:

  • 好的。那么如果被零除应该怎么办呢?
  • 当第3列为0时,你想做什么?忽略线?硬编码一些常量值?
  • 我猜是硬编码值 0。因为在百分位数计算中需要将其计为零。
  • 例如第1行:24676/218503341=0.0001,第2行:0.0129,第3行:0.14,第4行:0,第5行:0.035。然后找到这些数字的中位数 (0.0129)。

标签: linux bash awk


【解决方案1】:

有很多方法可以忽略除数为零的行,包括:

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

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

问题变了——改为打印 0。答案并不难:

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

中位数和其他百分位数更难处理。如果数据按排序顺序排列是最简单的。如此简单,我希望使用数字排序,然后从那里处理数据。


我挖出了一个旧的 shell 脚本,它计算描述性统计数据 - 单个数字列的最小值、最大值、众数、中位数和十分位数:

:   "@(#)$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);
    }'

minmax 的初始值并不完全科学。它可以说明一个观点。

(这个 1997 年的版本与其 1991 年的前身几乎相同 - 实际上,除了版本信息行是相同的。所以,代码已经有 20 多年的历史了。)

【讨论】:

  • 我实际上想要输出的百分位数。因此,如果我通过管道将其排序 -g,我需要选择 0.5*$NR
  • 您需要定义“输出的百分位数”的含义。你的意思是最接近第 N 个百分位的行,还是直到第 N 个百分位的所有行,或者...... 可以做什么的其他限制是什么?例如,我们是否可以通过sort 程序运行除法的输出,然后用第二个awk 脚​​本处理结果?
  • -是的,我们可以通过 sort 程序运行 dvision 的输出,然后使用第二个 awk 脚本处理结果。
  • 按中位数,我定义了中间值。通常,x% 百分位数是低于输出 x% 的值。我需要的是从第 1 列和第 3 列划分的任何百分位数。
【解决方案2】:

这里有一个解决方案:

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

如果第 3rd 列不为零,这将计算、打印和累加商。当它到达文件的末尾时(应该有一个空行),它将打印所有商的平均值和中位数,假设每一行都为 0,其中它会被零除.

awk中,$n表示nth字段,以1开头,$NR表示有记录数(即行数)被处理。每个商都存储在数组vals中,使我们能够计算中值。

在现实生活中,中位数定义为给定奇数个元素的“中间”项,或给定偶数个元素的两个“中间”项的平均值。

在实现sort 函数时,您只能靠自己!

【讨论】:

  • 这是平均值而不是中位数,不是吗?
  • 是的。我讨厌 awk 中的数组。 :-) 为什么你和我似乎回答了这么多相同的问题?
  • 我想这意味着我们有足够相似的背景,我们都可以回答类似的问题。 awk 中的数组可用于多种用途,但排序......不是 POSIX awk 中的内置功能(但在 GNU awk 中可用)。当然,Jon Bentley 在awk 中编写了一个完整的排序函数库,并在他的一本 Programming Pearls 书籍中编写了测试脚手架,因此可以在必要时完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-18
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
相关资源
最近更新 更多