我是一名计算机科学老师,正在尝试使用NumPy为自己创建一本小写本。但我认为如果我可以创建一个使用行和列的字段名称的ndarray,它将使我的代码更容易编写。这是我到目前为止所得到的:
import numpy as np
num_stud = 23
num_assign = 2
grades = np.zeros(num_stud, dtype=[('assign 1','i2'), ('assign 2','i2')]) #etc
gv = grades.view(dtype='i2').reshape(num_stud,num_assign)
所以,如果我的第一个学生获得97分'分配1',我可以写下:
grades[0]['assign 1'] = 97
gv[0][0] = 97
另外,我可以执行以下操作:
np.mean( grades['assign 1'] ) # class average for assignment 1
np.sum( gv[0] ) # total points for student 1
这一切都有效。但是我不能弄清楚如何做的是使用学生ID号来引用某个学生(假设我的两个学生有学生ID,如图所示):
grades['123456']['assign 2'] = 95
grades['314159']['assign 2'] = 83
...或者可能使用不同的字段名称创建第二个视图?
np.sum( gview2['314159'] ) # total points for the student with the given id
我知道我可以创建一个dict将学生ID映射到索引,但这似乎是脆弱和苛刻的,我希望有一个更好的方法:
id2i = { '123456': 0, '314159': 1 }
np.sum( gv[ id2i['314159'] ] )
如果有更清洁的设计,我也愿意重新设计。我是NumPy的新手,我还没有编写很多代码,所以如果我做错了,那么重新开始并不是不可能的。
我 am 需要每天为一百多名学生总结所有作业点,以及运行标准偏差和其他统计数据。另外,我会等待结果,所以我希望它能在几秒钟内运行。
提前感谢任何建议。
答案 0 :(得分:11)
从您的描述中,您最好使用与标准numpy数组不同的数据结构。 ndarray
不适合这个......它们不是电子表格。
然而,最近有关于一种numpy数组的广泛工作, 非常适合这种用途。关于DataArrays的最新工作的Here's a description。这将是一段时间才能完全融入numpy,但是......
即将推出的numpy DataArrays(基于)的项目之一是"larry"(“Labeled Array”的缩写)。这个项目听起来就像你想要做的那样...(已经命名了行和列,但在其他方面透明地作为一个numpy数组。)它应该足够稳定使用,(并且从我有限的玩弄它,它的非常光滑!)但请记住,它最终可能会被内置的numpy类所取代。
尽管如此,您可以充分利用这个事实,而不是(简单)索引numpy数组会将视图返回到该数组中,并创建一个提供这两个接口的类......
或者,@ unutbu上面的建议是另一种(更简单直接)的处理方式,如果你决定自己动手。
答案 1 :(得分:7)
为了输入和存储数据,我会使用关系数据库(如sqlite,MySQL或Postgresql)。如果这样做,您可以轻松编写多个程序,以不同的方式分析数据。可以从各种编程语言GUI / CLI接口访问sqlite数据库本身。您的数据将保持与语言无关(与存储numpy数组不同)。
Python内置了对sqlite的支持。
SQL为切片和切割数据提供了一种方便易读的语言(例如,“class1中的assignment1的所有分数是什么?”列出了10个最高分数。谁有这些分数?class1的平均值高于class2?)数据库表可以容纳多个类,多个学期。
为了输入数据,GUI可能是最方便的。对于sqlite,有sqlitebrowser(虽然我没有很多经验;可能有更好的选择。)。对于MySQL,我喜欢phpmyadmin,对于Postgresql,我喜欢phppgadmin。
输入数据后,可以使用Python模块(例如sqlite3,MySQLdb,pyscopg2)访问数据库,并发出SQL查询。然后可以将数据馈送到列表或numpy数组中。然后,您可以使用numpy来计算统计信息。
PS。对于小型数据集,确实没有关于速度或内存占用的问题。您不必将数据存储在numpy数组中以便调用 numpy / scipy统计函数。
例如,您可以从数据库中将数据绘制到Python列表中,并将Python列表提供给numpy函数:sql='SELECT * FROM grades WHERE assignment=%s'
args=['assign1']
data=cursor.fetchall(sql,args)
scores=zip(*data)[0]
ave_score=np.mean(scores)
如果成绩是一个numpy结构化数组,你将永远无法以这种方式访问值:
grades['123456']['assign 2']
因为列是按名称访问的,行是通过整数访问的。
但我不认为这会带来很多障碍。原因如下:你想为一个学生做的一切(比如找到所有作业点的总和),你可能想要为每个学生做。
因此numpy的技巧 - 利用其功能的方法 - 是编写矢量化方程式或使用同时应用于所有行的numpy函数,而不是单独循环行。 numpy鼓励你在更宏大的范围内思考(例如所有学生,所有任务),而不是单独考虑(如个别学生,个人作业)一次适用于所有这些的计算。
正如你所看到的那种与观点的争论,你实际上最好不要使用 结构化数组,而不选择普通的2轴numpy数组:
让我们假设列代表(2)分配,行代表(4)学生。
In [36]: grades=np.random.random((4,2))
In [37]: grades
Out[37]:
array([[ 0.42951657, 0.81696305],
[ 0.2298493 , 0.05389136],
[ 0.12036423, 0.78142328],
[ 0.5029192 , 0.75186565]])
以下是一些统计数据:
In [38]: sum_of_all_assignments = grades.sum(axis=1)
In [39]: sum_of_all_assignments
Out[39]: array([ 1.24647962, 0.28374066, 0.90178752, 1.25478485])
In [40]: average_of_all_assignments = grades.mean(axis=1)
In [41]: average_of_all_assignments
Out[41]: array([ 0.62323981, 0.14187033, 0.45089376, 0.62739242])
In [42]: average_assignment_score = grades.mean(axis=0)
In [43]: average_assignment_score
Out[43]: array([ 0.32066233, 0.60103583])
现在假设这些是学生的名字:
In [44]: student_names=['harold','harry','herb','humphrey']
要将学生姓名与其平均分数相匹配,您可以创建字典
In [45]: dict(zip(student_names,average_of_all_assignments))
Out[45]:
{'harold': 0.62323981076528523,
'harry': 0.14187032892653173,
'herb': 0.45089375919011698,
'humphrey': 0.62739242488169067}
同样,对于作业:
In [46]: assignment_names=['assign 1','assign 2']
In [47]: dict(zip(assignment_names,average_assignment_score))
Out[47]: {'assign 1': 0.32066232713749887, 'assign 2': 0.60103583474431344}
答案 2 :(得分:4)
你应该看看pandas模块,它完全符合你的需要。 http://pandas.pydata.org