假设我有一个结构化的学生数组(字符串)和测试分数(整数),其中每个条目是特定学生在特定考试中获得的分数。每个学生自然会在这个数组中有多个条目。
import numpy
grades = numpy.array([('Mary', 96), ('John', 94), ('Mary', 88), ('Edgar', 89), ('John', 84)],
dtype=[('student', 'a50'), ('score', 'i')])
print grades
#[('Mary', 96) ('John', 94) ('Mary', 88) ('Edgar', 89) ('John', 84)]
如何轻松计算每个学生的平均分数?换句话说,我如何在“得分”维度中取得数组的均值?我想做
grades.mean('score')
并且Numpy返回
[('Mary', 92), ('John', 89), ('Edgar', 89)]
但是Numpy抱怨
TypeError: an integer is required
有一种Numpy式的方式可以轻松地做到这一点吗?我认为这可能涉及使用不同的dtype查看结构化数组。任何帮助,将不胜感激。感谢。
>>> grades = numpy.zeros(5, dtype=[('student', 'a50'), ('score', 'i'), ('testid', 'i'])
>>> grades[0] = ('Mary', 96, 1)
>>> grades[1] = ('John', 94, 1)
>>> grades[2] = ('Mary', 88, 2)
>>> grades[3] = ('Edgar', 89, 1)
>>> grades[4] = ('John', 84, 2)
>>> np.mean(grades, 'testid')
TypeError: an integer is required
答案 0 :(得分:4)
NumPy的设计不能将行组合在一起,并将聚合函数应用于这些组。你可以:
itertools.groupby
并重建数组; 这是itertools
解决方案,但正如您所看到的那样,它非常复杂且效率低下。我推荐其他两种方法之一。
np.array([(k, np.array(list(g), dtype=grades.dtype).view(np.recarray)['score'].mean())
for k, g in groupby(np.sort(grades, order='student').view(np.recarray),
itemgetter('student'))], dtype=grades.dtype)
答案 1 :(得分:1)
matplotlib.mlab.rec_groupby正是我想要的。
答案 2 :(得分:0)
基于itertools
而不使用view()的更快更简单的解决方案是
[(k,e['score'][list(g)].mean()) for k, g in groupby(argsort(e),e['student'].__getitem__ )]
这与ecatmur的想法相同,但是在使用argsort()而不是sort的索引方面起作用。
答案 3 :(得分:0)
collapseByField(成绩,'学生')给出了你想要的东西:
def collapseByField(e,collapsefield,keepFields=None,agg=None):
import numpy as np
assert isinstance(e,np.ndarray) # Structured array
if agg is None:
agg=np.mean
if keepFields is None:
newf=[(n,agg,n) for n in e.dtype.names if n not in (collapsefield)]
import matplotlib as mpl
return(mpl.mlab.rec_groupby(e,[collapsefield],newf))