行和列的ndarray字段名称?

时间:2010-10-11 22:08:34

标签: python numpy

我是一名计算机科学老师,正在尝试使用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 需要每天为一百多名学生总结所有作业点,以及运行标准偏差和其他统计数据。另外,我会等待结果,所以我希望它能在几秒钟内运行。

提前感谢任何建议。

3 个答案:

答案 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