Linux 命令行上的 csv 平均值

Linux 命令行上的 csv 平均值

我有一个大文件,里面全是这样的记录

1, 2, 4, 5, 6
1, 3, 5, 6, 3
1, 4, 5, 6, 6
2, 4, 5, 5, 5
2, 3, 4, 5, 2

无论如何,我需要对具有相同第一个数字(键)的所有行取平均值。即

1, 3, 4.66, 5.66, 5
2, 3.5, 4.5, 5, 3.5

我知道 awk/sed 非常适合做这件事,但我只是没有足够的经验来完成它,谢谢!

另外,如何将这些列平均在一起?因此,在我将其输出到文件后,我希望得到另一个类似的结果:

1, 4.58
1, 4.125

要添加的列数也可能不总是 4。

编辑:这可能在 gnuplot 中更容易做到,所以我主要只需要对第一部分的答案。

答案1

对于第一个选项:

awk -F, 'BEGIN { OFS=","} {if (!keys[$1]) {keys[$1] = 1}; for (i=2;i<=NF;i++){array[$1,i]+=$i}; count[$1]+=1}END{for (i in keys) {printf ("%s ", i); for (j=2;j<=NF;j++) {printf ("%.2f ", array[i,j]/count[i])}; printf ("%s","\n")}}' inputfile

对于第二种选择:

awk -F, 'BEGIN { OFS=","} {if (!keys[$1]) {keys[$1] = 1}; for (i=2;i<=NF;i++){array[$1,i]+=$i}; count[$1]+=1}END{for (i in keys) {{printf ("%s ", i); sum = 0; for (j=2;j<=NF;j++) {sum += array[i,j]/count[i]}}; printf ("%.2f\n",sum/(NF-1))}}' inputfile

但我不确定我是否理解你为什么想要一些平均值的平均值。

答案2

使用 Sed 来实现这一点出奇地棘手和复杂,因此这里有一个 Python 技巧可以做到这一点:

#!/usr/bin/env python

f = open("mycsv","r")
values = {}
index = {}
for line in f:
    rownum = line.strip().split(", ")
    try:
        values[rownum[0]] = map(lambda x,y: x+y, values[rownum[0]], [float(x) for x in rownum[1:]])
        index[rownum[0]] += 1
    except KeyError:
        values[rownum[0]] = [ float(x) for x in rownum[1:] ]
        index[rownum[0]] = 1

for k,v in values.items():
    values[k] = [x/index[k] for x in values[k]]
    print k, ":", values[k]

无论行的顺序如何,此方法都有效,只要具有相同第一个元素的行的长度相同。

计算各列的平均数只需要在 Python 的 for 循环中添加一行代码:

print reduce(lambda x,y: x+y, values[k])/len(values[k])

不过,考虑到列表推导的数量令人担忧,您最好使用 NumPy 或 Matlab 来解决这个问题。

答案3

Karthik 对在 Numpy 中实现这一点提出了一个很好的建议:只需几行,

import numpy
data = numpy.loadtxt('filename.txt')
for key in numpy.unique(data.T[0]):
    print data[data.T[0]==key].mean(0)

或者如果你想要计算各列的平均值,最后一行将更改为

    avgs = data[data.T[0]==key].mean(0)[1:]
    print avgs[0], avgs[1:].mean()

相关内容