计算一列的平均值

时间:2019-06-19 17:48:36

标签: awk

我有一个制表符delim文件

LOC105758527    1       55001   0.469590
LOC105758527    1       65001   0.067909
LOC105758527    1       75001   0.220712
LOC100218126    1       85001   0.174872
LOC105758529    1       125001  0.023420
NRF1    1       155001  0.242222
NRF1    1       165001  0.202569
NRF1    1       175001  0.327963
UBE2H   1       215001  0.063989
UBE2H   1       225001  0.542340
KLHDC10 1       255001  0.293471
KLHDC10 1       265001  0.231621
KLHDC10 1       275001  0.142917
TMEM209 1       295001  0.273941
CPA2    1       315001  0.181312

我需要为col 1中的每个元素计算col 4的平均值,因此求和/行数并在计算中打印第一行的col1,2,3并将平均值打印为col 4。

我从做和开始

awk 'BEGIN { FS = OFS = "\t" }
        { y[$1] += $4; $4 = y[$1]; x[$1] = $0; }
END { for (i in x) { print x[i]; } }' file

但是我得到

NRF1    1       175001  0.772754
LOC105758529    1       125001  0.02342
LOC100218126    1       85001   0.174872
KLHDC10 1       275001  0.668009
CPA2    1       315001  0.181312
TMEM209 1       295001  0.273941
UBE2H   1       225001  0.606329
LOC105758527    1       75001   0.758211

这意味着它正在跳到文件中第一行以外的其他行(并从计算出的最后一行开始打印col1,2,3-很好,但我更喜欢第一行)。输出不正常。

我也不知道如何将总和除以他们的NR以得到平均值

3 个答案:

答案 0 :(得分:1)

这可以通过使用数组存储行顺序和中间计算步骤在awk中完成:

# set fields delimiters
BEGIN { FS = OFS = "\t" }

# print the header
NR==1 { print; next }

# the first time col1 value occurs, store col1..col3
!h[$1] {
    h[$1] = ++n  # save ordering
    d[n] = $1 OFS $2 OFS $3  # save first 3 columns
}

# store sum and quantity of col4
{
    i = h[$1]  # recover ordering
    s[i] += $4
    q[i]++
}

# output col1..col3 and the average value
END {
    for (i=1; i<=n; i++) print d[i], s[i]/q[i]
}

自从我撰写以上内容后,我看到您已经编辑了问题。如果您的数据没有标题,则不需要NR==1行。

如果您的数据文件确实很大,则上面的脚本可能会消耗过多的内存(它将使用与col1唯一值数量成比例的内存)。如果这将成为问题,并且输出行的顺序并不重要,则可以通过对数据进行预排序(也许使用sort -k1,1 -s)并逐步产生输出来大大减少内存使用量:

BEGIN { FS = OFS = "\t" }

$1 != c1 {
    if (c1) print d, s/q
    d = $1 OFS $2 OFS $3
    s = q = 0
    c1 = $1
}

{
    s += $4
    q++
}

END { print d, s/q }

答案 1 :(得分:1)

这是awk脚本尝试。不确定我是否做了很多更改就完全理解了任务。

script.awk

BEGIN {OFS="\t"}  # assign output field separtor to tab
$1 == currFields[1]{  # handle a repeated line
    lineCount++;      # increment line counter
    currFields[4] += $4; # accumulate the sum of 4th field
    next;             # skip any output and read next line.
}
{                     # handle a new line not seen before
    outputPrevLine(); # print out the prvious line
    for(i = 1; i <= NF; i++) currFields[i] = $i; # store current line values
    lineCount = 0;    # reset line counter
}
END {outputPrevLine();} # output the last line even if repeated.
function outputPrevLine() { 
    if (NR == 1) return; # discard first line, since it contains no value.
    print currFields[1], currFields[2], currFields[3], currFields[4]/(lineCount + 1);
}

input.txt

LOC105758527    1       55001   0.469590
LOC105758527    1       65001   0.067909
LOC105758527    1       75001   0.220712
LOC100218126    1       85001   0.174872
LOC105758529    1       125001  0.023420
NRF1    1       155001  0.242222
NRF1    1       165001  0.202569
NRF1    1       175001  0.327963
UBE2H   1       215001  0.063989
UBE2H   1       225001  0.542340
KLHDC10 1       255001  0.293471
KLHDC10 1       265001  0.231621
KLHDC10 1       275001  0.142917
TMEM209 1       295001  0.273941
CPA2    1       315001  0.181312

运行:

 sort input.txt | awk -f script.awk 

输出:

CPA2    1       315001  0.181312
KLHDC10 1       255001  0.22267
LOC100218126    1       85001   0.174872
LOC105758527    1       55001   0.252737
LOC105758529    1       125001  0.02342
NRF1    1       155001  0.257585
TMEM209 1       295001  0.273941
UBE2H   1       215001  0.303165

答案 2 :(得分:0)

因为我想不出如何索引数组以及如何将总和除以计数 我对此的解决方案是对

的输出进行排序
awk 'BEGIN { FS = OFS = "\t" }
        { y[$1] += $4; $4 = y[$1]; x[$1] = $0; }
END { for (i in x) { print x[i]; } }' file | sort -V -k2,3 > temp1

并将其保存到temp1文件中。

然后计算原始文件中col1中的uniq出现次数,并通过执行一些文本重新格式化

cut -f1 test | uniq -c | sed 's/^\s\+//g ; s/\s/\t/' > temp2

并保存到temp2文件

然后我只是粘贴temp1和temp2,然后将sum列除以count列

paste temp1 temp2 | awk -F$'\t' '{$6 = $4 / $5}1' > output

最后4个col是总和,第5个col是计数,第6个col是平均值

LOC105758527  1  75001   0.758211  3  0.252737
LOC100218126  1  85001   0.174872  1  0.174872
LOC105758529  1  125001  0.02342   1  0.02342
NRF1          1  175001  0.772754  3  0.257585
UBE2H         1  225001  0.606329  2  0.303165
KLHDC10       1  275001  0.668009  3  0.22267
TMEM209       1  295001  0.273941  1  0.273941
CPA2          1  315001  0.181312  1  0.181312

然后生成rm临时文件