首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用awk计算滑动窗的中位数

用awk计算滑动窗的中位数
EN

Stack Overflow用户
提问于 2020-03-24 21:43:29
回答 3查看 307关注 0票数 5

我需要生成一个数百万行的滑动窗口,并计算第3列的中位数。我的数据如下所示,第1列总是相同的,第2列等于行号,第3列是我需要中位数的信息:

代码语言:javascript
复制
HiC_scaffold_1  1   34
HiC_scaffold_1  2   34
HiC_scaffold_1  3   36
HiC_scaffold_1  4   37
HiC_scaffold_1  5   38
HiC_scaffold_1  6   39
HiC_scaffold_1  7   40
HiC_scaffold_1  8   40
HiC_scaffold_1  9   40
HiC_scaffold_1  10  41
HiC_scaffold_1  11  41
HiC_scaffold_1  12  41
HiC_scaffold_1  13  44
HiC_scaffold_1  14  44
HiC_scaffold_1  15  55

我需要一个这样的结果,假设滑动窗口为4,四舍五入到最接近的整数。在真实数据集中,我可能会使用1000的滑动窗口:

代码语言:javascript
复制
HiC_scaffold_1  4   35
HiC_scaffold_1  5   37
HiC_scaffold_1  6   38
HiC_scaffold_1  7   39
HiC_scaffold_1  8   40
HiC_scaffold_1  9   40
HiC_scaffold_1  10  40
HiC_scaffold_1  11  41
HiC_scaffold_1  12  41
HiC_scaffold_1  13  41
HiC_scaffold_1  14  43
HiC_scaffold_1  15  44

我找到了下面的脚本here,用来做我想做的事情,但是是均值,而不是中值:

代码语言:javascript
复制
awk -v OFS="\t" 'BEGIN {
        window = 4
        slide = 1
}

{
        mod = NR % window
        if (NR <= window) {
                count++
        } else {
                sum -= array[mod]
        }
        sum += $3
        array[mod] = $3
}

(NR % slide) == 0 {
        print $1, NR, sum / count
}
' file.txt

此脚本用于使用here中的awk计算中位数

代码语言:javascript
复制
sort -n -k3 file.txt |
awk '{
        arr[NR] = $3
}

END {
        if (NR % 2 == 1) {
                print arr[(NR + 1) / 2]
        } else {
                print $1 "\t" $2 "\t" (arr[NR / 2] + arr[NR / 2 + 1]) / 2
        }
}
'

但我不能让他们一起工作。另一个问题是,中位数计算需要排序输入。我也找到了这个datamash解决方案,但我不知道如何有效地使用滑动窗口。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-03-24 22:36:01

下面假设函数asort是可用的,由GNU awk (gawk)提供。该程序由wsize (窗口大小)参数化--此处为4:

代码语言:javascript
复制
gawk -v wsize=4 '
   BEGIN { 
    if (wsize % 2 == 0) { m1=wsize/2; m2=m1+1; } else { m1 = m2 = (wsize+1)/2; } 
   }
   function roundedmedian() {
     asort(window, a);
     return (m1==m2) ? a[m1] : int(0.5 + ((a[m1] + a[m2]) / 2));
   }
   function push(value) {
     window[NR % wsize] = value;
   }
   NR < wsize { window[NR]=$3; next; }
   { push($3);
     $3 = roundedmedian();
     print $0;
   }' 
票数 4
EN

Stack Overflow用户

发布于 2020-03-24 22:40:01

使用GNU awk for asort()

代码语言:javascript
复制
$ cat tst.awk
BEGIN {
    OFS = "\t"
    window = 4
    befMid = int(window / 2)
    aftMid = befMid + (window % 2 ? 0 : 1)
}
{ array[NR % window] = $3 }
NR >= window {
    asort(array,vals)
    print $1, $2, int( (vals[befMid] + vals[aftMid]) / 2 + 0.5 )
}

代码语言:javascript
复制
$ awk -f tst.awk file
HiC_scaffold_1  4       35
HiC_scaffold_1  5       37
HiC_scaffold_1  6       38
HiC_scaffold_1  7       39
HiC_scaffold_1  8       40
HiC_scaffold_1  9       40
HiC_scaffold_1  10      40
HiC_scaffold_1  11      41
HiC_scaffold_1  12      41
HiC_scaffold_1  13      41
HiC_scaffold_1  14      43
HiC_scaffold_1  15      44
票数 4
EN

Stack Overflow用户

发布于 2020-03-24 22:11:01

下面的GNU awk脚本似乎生成了您所呈现的输出:

代码语言:javascript
复制
awk -v OFS='\t' -v window=4 '
{
    # I store the numbers in an array `nums` indexed with `1 ... window`
    mod = NR % window + 1;
    nums[mod] = $3;
}

# If the count of numbers is greater or equal the window,
# we can start calculating the median.
NR >= window {

    # Copy the array nums, cause we need to sort it.
    for (i = 1; i <= window; ++i) {
        copy[i] = nums[i];
    }

    # Sort the copy.
    # asort is a GNU extension if I remember.
    # For non-gnu, write a sorting function yourself.
    asort(copy);

    # Calculate the median.
    # I hope that is ok.
    half = int( (window + 1) / 2 );
    if (window % 2 == 0) {
        # You seem to want to round 0.5 up.
        # Just add 1 and round down.
        median = int( (copy[half] + copy[half + 1] + 1) / 2 );
    } else {
        median = copy[half];
    }

    # Output
    print $1, $2, median 
}'
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60832286

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档