我有一个大文件,里面全是这样的记录
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()