2015-07-21 39 views
0

我有五个不同的文件。每个文件的部分看起来:使用Shell不考虑缺失值的多个文件的平均数

ifile1.txt ifile2.txt ifile3.txt ifile4.txt ifile5.txt 
    2   3   2   3   2 
    1   2   /no value  2   3 
/no value  2   4   3  /no value 
    3   1   0   0   1 
/no value /no value /no value /no value /no value 

我需要计算这五个文件的平均不考虑遗漏值。即

ofile.txt 
    2.4 
    2.0 
    3.0 
    1.0 
    99999 

Here 2.4 = (2+3+2+3+2)/5 
    2.0 = (1+2+2+3)/4 
    3.0 = (2+4+3)/3 
    1.0 = (3+1+0+0+1)/5 
    99999 = all are missing 

我试图用下面的方式,但不觉得它是一个正确的方法。

paste ifile1.txt ifile2.txt ifile3.txt ifile4.txt ifile5.txt > ofile.txt 
tr '\n' ' ' <ofile.txt> ofile1.txt 
awk '!/\//{sum += $1; count++} {print count ? (sum/count) : count;sum=count=0}' ofile1.txt > ofile2.txt 
awk '!/\//{sum += $2; count++} {print count ? (sum/count) : count;sum=count=0}' ofile1.txt > ofile3.txt 
awk '!/\//{sum += $3; count++} {print count ? (sum/count) : count;sum=count=0}' ofile1.txt > ofile4.txt 
awk '!/\//{sum += $4; count++} {print count ? (sum/count) : count;sum=count=0}' ofile1.txt > ofile5.txt 
awk '!/\//{sum += $5; count++} {print count ? (sum/count) : count;sum=count=0}' ofile1.txt > ofile6.txt 
paste ofile2.txt ofile3.txt ofile4.txt ofile5.txt ofile6.txt > ofile7.txt 
tr '\n' ' ' <ofile7.txt> ofile.txt 
+1

你尝试过什么,并且你遇到什么问题?堆栈溢出不是其他人为您编写代码的网站。 –

+1

我很抱歉让你感觉如此。老实说,我从过去两天开始一直在尝试,但无法以适当的方式去做。无论如何,我已经更新了我尝试过的问题。 – Kay

回答

2

以下script.awk将提供你想要的东西:

BEGIN { 
    gap = -1; 
    maxidx = -1; 
} 
{ 
    if (NR != FNR + gap) { 
     idx = 0; 
     gap = NR - FNR; 
    } 
    if (idx > maxidx) { 
     maxidx = idx; 
     count[idx] = 0; 
     sum[idx] = 0; 
    } 
    if ($0 != "/no value") { 
     count[idx]++; 
     sum[idx] += $0; 
    } 
    idx++; 
} 
END { 
    for (idx = 0; idx <= maxidx; idx++) { 
     if (count[idx] == 0) { 
      sum[idx] = 99999; 
      count[idx] = 1; 
     } 
     print sum[idx]/count[idx]; 
    } 
} 

你与调用它:

awk -f script.awk ifile*.txt 

,并允许输入文件的任意号码,每一个任意行数。它的工作原理如下:


BEGIN { 
    gap = -1; 
    maxidx = -1; 
} 

此开始的行进行处理,并将其设置当前间隙,并相应地最大索引之前部分延伸。

的差距是整体的行号NR和文件行号FNR,用于当您切换文件进行检测,一些处理多个输入文件时是非常方便的区别。

最大索引用于计算出最大行数,以便在最后输出正确数量的记录。


{ 
    if (NR != FNR + gap) { 
     idx = 0; 
     gap = NR - FNR; 
    } 
    if (idx > maxidx) { 
     maxidx = idx; 
     count[idx] = 0; 
     sum[idx] = 0; 
    } 
    if ($0 != "/no value") { 
     count[idx]++; 
     sum[idx] += $0; 
    } 
    idx++; 
} 

上面的代码是该溶液中,每行执行的肉。第一个if语句用于检测您是否刚刚移动到一个新文件中,并且它是这样做的,因此它可以汇总每个文件中的所有相关行。我的意思是每个输入文件的第一行用于计算输出文件第一行的平均值。

第二个if语句会调整maxidx如果当前行号超出我们遇到的任何以前的行号。这是为了文件一可能有七行,但文件二有九行(在你的情况不是这样,但它是值得处理的)。以前未知的行号也意味着我们初始化它的总和并计数为零。

最后的if声明只是更新总和并计算该行是否包含除/no value以外的任何内容。

然后,当然,您需要调整下一次的行号。


END { 
    for (idx = 0; idx <= maxidx; idx++) { 
     if (count[idx] == 0) { 
      sum[idx] = 99999; 
      count[idx] = 1; 
     } 
     print sum[idx]/count[idx]; 
    } 
} 

在输出该数据的条件,它是通过阵列去和从所述总和计算的平均值和计数一件简单的事情。请注意,如果计数为零(所有对应条目均为/no value),我们调整总数并计数,以获得99999。然后我们只打印平均值。


所以,运行该代码在你输入文件给出,如要求:

$ awk -f script.awk ifile*.txt 
2.4 
2 
3 
1 
99999 
+0

这真是太棒了@paxdiablo。如果我需要计算标准偏差,你能建议我吗? – Kay

0

使用bashnumaverage(而忽略非数字输入),加上pastesedtr(均为清洁,因为numaverage需要单列输入,并且如果输入是100% text)会引发错误:

paste ifile* | while read x ; do \ 
        numaverage <(tr '\t' '\n' <<< "$x") 2>&1 | \ 
        sed -n '1{s/Emp.*/99999/;p}' ; \ 
       done 

输出:

2.4 
2 
3 
1 
99999