我有一个制表符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以得到平均值
答案 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临时文件