【问题标题】:Find linear trend up to the maximum value using awk使用 awk 查找直到最大值的线性趋势
【发布时间】:2020-07-01 08:23:41
【问题描述】:

我有一个数据文件如下:

ifile.txt

-10     /
-9      /
-8      /
-7      3
-6      4
-5      13
-4      16
-3      17
-2      23
-1      26
0       29
1       32
2       35
3       38
4       41
5       40
6       35
7       30
8       25
9       /
10      /

这里的“/”是缺失值。我想计算线性趋势,直到 y 轴上的最大值(即,直到第二列中的值“41”)。所以它应该从以下数据计算趋势:

-7      3
-6      4
-5      13
-4      16
-3      17
-2      23
-1      26
0       29
1       32
2       35
3       38
4       41

其他 (x, y) 将不考虑,因为 (4, 41) 之后的 y 值小于 41

以下脚本适用于所有值:

awk '!/\//{sx+=$1; sy+=$2; c++;
                    sxx+=$1*$1; sxy+=$1*$2}
           END     {det=c*sxx-sx*sx;
                    print (det?(c*sxy-sx*sy)/det:"DIV0")}' ifile.txt

但我无法做到最大价值

For the given example the result will be 3.486

【问题讨论】:

    标签: shell awk trendline


    【解决方案1】:

    根据您的 cmets 更新。我假设你的趋势计算很好并使用了它们:

    $ awk '
    $2!="/" {
        b1[++j]=$1                            # buffer them up until or if used
        b2[j]=$2
        if(max=="" || $2>max) {               # once a bigger than current max found
            max=$2                            # new champion
            for(i=1;i<=j;i++) {               # use all so far buffered values
                # print  b1[i], b2[i]         # debug to see values used
                sx+=b1[i]                     # Your code from here on
                sy+=b2[i]
                c++
                sxx+=b1[i]*b1[i]
                sxy+=b1[i]*b2[i]
            }
            j=0                               # buffer reset
            delete b1
            delete b2
        }
    }
    END {
        det=c*sxx-sx*sx
        print (det?(c*sxy-sx*sy)/det:"DIV0")
    }' file
    

    对于数据:

    0       /
    1       1
    2       2
    3       4
    4       3
    5       5
    6       10
    7       7
    8       8
    

    使用调试print 未注释的程序将输出:

    1 1
    2 2
    3 4
    4 3
    5 5
    6 10
    1.51429
    

    【讨论】:

    • 看来这个脚本正在考虑所有小于 41 的 y 值。但我正在寻找趋势直到最大 y。超出最大值 y 的 (x , y) 值不应计入该帐户。非常感谢你。我已经更新了问题。
    • @Kay 它接受所有增加的 y 值,例如从集合 (1,2,4,3,5) 它将使用 (1,2,4,5) 所以在你的例子中它会采用高达 41 的值.
    • 谢谢。我正在寻找最大 y 的所有条目的趋势。从您的示例中,假设 y,从集合 (1,2,4,3,5) 中,它应该考虑所有 (1,2,4,3,5),因为 5 是最大值。类似地,对于集合 (1,2,4,3,5,4,3),它应该考虑 (1,2,4,3,5),因为最大值是 5,所以 5 之后的数字即 4 和 3 赢了不考虑。另一个例子可能是,从集合 (1,2,4,3,5,10,7,8) 中,它会考虑 (1,2,4,3,5,10)`,它不应该考虑 7和 8,因为它们将在 10 之后到来。
    • 根据您的 cmets 更新。
    【解决方案2】:

    只有在$2 &gt; max 时才可以更新相关行,并将中间行保存到变量中。例如使用关联数组:

    awk '
      $2 == "/" {next}
      $2 > max {
        # update max if $2 > max
        max = $2;
        # add all elemenet of a1 to a and b1 to b
        for (k in a1) {
          a[k] = a1[k]; b[k] = b1[k]
        }
        # add the current row to a, b
        a[NR] = $1; b[NR] = $2; 
        # reset a1, b1
        delete a1; delete b1;
        next;
      }
      # if $2 <= max, then set a1, b1
      { a1[NR] = $1; b1[NR] = $2 }
      END{
        for (k in a) {
          #print k, a[k], b[k]
          sx += a[k]; sy += b[k]; sxx += a[k]*a[k]; sxy += a[k]*b[k]; c++
        }
        det=c*sxx-sx*sx;
        print (det?(c*sxy-sx*sy)/det:"DIV0")
      }
    ' ifile.txt
    #3.48601
    

    或者直接计算sx、sy等,而不是使用数组:

    awk '
      $2 == "/" {next}
      $2 > max {
        # update max if $2 > max
        max = $2;
        # add the current Row plus the cached values
        sx += $1+sx1; sy += $2+sy1; sxx += $1*$1+sxx1; sxy += $1*$2+sxy1; c += 1+c1
        # reset the cached variables
        sx1 = 0; sy1 = 0; sxx1 = 0; sxy1 = 0; c1 = 0;
        next;
      }
      # if $2 <= max, then calculate and cache the values
      { sx1 += $1; sy1 += $2; sxx1 += $1*$1; sxy1 += $1*$2; c1++ }
      END{
        det=c*sxx-sx*sx;
        print (det?(c*sxy-sx*sy)/det:"DIV0")
      }
    ' ifile.txt
    

    【讨论】:

    • 是的。它工作得很好。非常感谢。赏金现在是你的了。还需要 20 个小时才能得到这个。
    • 只是好奇,我的解决方案有什么问题吗?
    • 您的解决方案非常好。我只是在分配信用。我答应给你赏金。很抱歉给您带来不便。
    猜你喜欢
    • 1970-01-01
    • 2020-01-16
    • 2022-01-14
    • 2022-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    相关资源
    最近更新 更多