Numpy 中的命名元组
Namedtuple in Numpy
我真的很喜欢 namedtuple 集合的功能。具体来说,我喜欢它对二维 space.
中的点有多么有用
In : from collections import namedtuple
In : Point = namedtuple('Point', ['x', 'y'])
In : p = Point(1,2)
In : p.x
Out: 1
In : p.y
Out: 2
我认为这比引用列表的第一个和第二个条目要清楚得多。我想知道是否有办法使 Point 也是一个 numpy 数组。例如
In: p1 = Point(1,2)
In: p2 = Point(3,4)
In: (p1+p2).x
Out: 4
以及来自 numpy 的类似功能。换句话说,我想我想让 Point 成为 numpy 的子类?我可以这样做吗?又如何?
您可以使用 numpy 的 structured arrays:
获得一些类似的功能
In [36]: import numpy as np
...: point_type = [('x', float), ('y', float)]
...: points = np.array([(1,2), (3,4), (5,6)], dtype=point_type)
In [37]: points[2]
Out[37]: (5.0, 6.0)
In [38]: points['x']
Out[38]: array([ 1., 3., 5.])
甚至可以通过将结构数组转换为 recarray:
来使用属性访问(例如使用 points.x
)使所有字段可用
In [39]: pts = points.view(np.recarray)
In [40]: pts['x']
Out[40]: array([ 1., 3., 5.])
In [41]: pts.x
Out[41]: array([ 1., 3., 5.])
In [42]: pts[2]
Out[42]: (5.0, 6.0)
请注意,recarray 显然存在一些性能问题,使用起来可能有点烦人。您可能还想查看 pandas 库,它也允许按属性访问字段,并且没有 recarray 的问题。
像point_type
这样的结构化数组没有定义涉及多个字段的数学运算。
样本来自
In [470]: point_type = [('x', float), ('y', float)]
In [471]: points = np.array([(1,2), (3,4), (5,6)], dtype=point_type)
In [472]: points
Out[472]:
array([(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
In [473]: points[0]+points[1]
...
TypeError: unsupported operand type(s) for +: 'numpy.void' and 'numpy.void'
相反,我可以创建一个二维数组,然后将其视为 point_type
- 数据缓冲区布局将相同:
In [479]: points = np.array([(1,2), (3,4), (5,6)],float)
In [480]: points
Out[480]:
array([[ 1., 2.],
[ 3., 4.],
[ 5., 6.]])
In [481]: points.view(point_type)
Out[481]:
array([[(1.0, 2.0)],
[(3.0, 4.0)],
[(5.0, 6.0)]],
dtype=[('x', '<f8'), ('y', '<f8')])
In [482]: points.view(point_type).view(np.recarray).x
Out[482]:
array([[ 1.],
[ 3.],
[ 5.]])
我可以跨行做数学运算,并继续以点的形式查看结果:
In [483]: (points[0]+points[1]).view(point_type).view(np.recarray)
Out[483]:
rec.array([(4.0, 6.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
In [484]: _.x
Out[484]: array([ 4.])
In [485]: points.sum(0).view(point_type)
Out[485]:
array([(9.0, 12.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
或者我可以从 point_type
开始,将其视为数学的 2d,然后再查看
pdt1=np.dtype((float, (2,)))
In [502]: points
Out[502]:
array([(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
In [503]: points.view(pdt1)
Out[503]:
array([[ 1., 2.],
[ 3., 4.],
[ 5., 6.]])
In [504]: points.view(pdt1).sum(0).view(point_type)
Out[504]:
array([(9.0, 12.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
因此可以将数组作为 2d 和 recarray 查看和操作。为了漂亮或有用,它可能需要埋在用户定义的 class.
中
从 recarray
class 抄袭想法的另一种选择。它的核心只是一个结构化数组,带有专门的 __getattribute__
(和 setattribute)方法。该方法首先尝试普通数组方法和属性(例如 x.shape
、x.sum
)。然后它尝试在定义的字段名中调整 attr
。
def __getattribute__(self, attr):
try:
return object.__getattribute__(self, attr)
except AttributeError: # attr must be a fieldname
pass
fielddict = ndarray.__getattribute__(self, 'dtype').fields
try:
res = fielddict[attr][:2]
except (TypeError, KeyError):
raise AttributeError("record array has no attribute %s" % attr)
return self.getfield(*res)
...
points.view(np.recarray).x
变为 points.getfield(*points.dtype.fields['x'])
.
另一种方法是借鉴 namedtuple
(/usr/lib/python3.4/collections/__init__.py
),并定义 x
和 y
属性,这将索引 [:,0]
和二维数组的 [:,1]
列。
将这些属性添加到 np.matrix
的子 class 可能是最简单的方法,让 class 确保大多数数学结果是二维的。
我真的很喜欢 namedtuple 集合的功能。具体来说,我喜欢它对二维 space.
中的点有多么有用In : from collections import namedtuple
In : Point = namedtuple('Point', ['x', 'y'])
In : p = Point(1,2)
In : p.x
Out: 1
In : p.y
Out: 2
我认为这比引用列表的第一个和第二个条目要清楚得多。我想知道是否有办法使 Point 也是一个 numpy 数组。例如
In: p1 = Point(1,2)
In: p2 = Point(3,4)
In: (p1+p2).x
Out: 4
以及来自 numpy 的类似功能。换句话说,我想我想让 Point 成为 numpy 的子类?我可以这样做吗?又如何?
您可以使用 numpy 的 structured arrays:
获得一些类似的功能In [36]: import numpy as np
...: point_type = [('x', float), ('y', float)]
...: points = np.array([(1,2), (3,4), (5,6)], dtype=point_type)
In [37]: points[2]
Out[37]: (5.0, 6.0)
In [38]: points['x']
Out[38]: array([ 1., 3., 5.])
甚至可以通过将结构数组转换为 recarray:
来使用属性访问(例如使用points.x
)使所有字段可用
In [39]: pts = points.view(np.recarray)
In [40]: pts['x']
Out[40]: array([ 1., 3., 5.])
In [41]: pts.x
Out[41]: array([ 1., 3., 5.])
In [42]: pts[2]
Out[42]: (5.0, 6.0)
请注意,recarray 显然存在一些性能问题,使用起来可能有点烦人。您可能还想查看 pandas 库,它也允许按属性访问字段,并且没有 recarray 的问题。
像point_type
这样的结构化数组没有定义涉及多个字段的数学运算。
样本来自
In [470]: point_type = [('x', float), ('y', float)]
In [471]: points = np.array([(1,2), (3,4), (5,6)], dtype=point_type)
In [472]: points
Out[472]:
array([(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
In [473]: points[0]+points[1]
...
TypeError: unsupported operand type(s) for +: 'numpy.void' and 'numpy.void'
相反,我可以创建一个二维数组,然后将其视为 point_type
- 数据缓冲区布局将相同:
In [479]: points = np.array([(1,2), (3,4), (5,6)],float)
In [480]: points
Out[480]:
array([[ 1., 2.],
[ 3., 4.],
[ 5., 6.]])
In [481]: points.view(point_type)
Out[481]:
array([[(1.0, 2.0)],
[(3.0, 4.0)],
[(5.0, 6.0)]],
dtype=[('x', '<f8'), ('y', '<f8')])
In [482]: points.view(point_type).view(np.recarray).x
Out[482]:
array([[ 1.],
[ 3.],
[ 5.]])
我可以跨行做数学运算,并继续以点的形式查看结果:
In [483]: (points[0]+points[1]).view(point_type).view(np.recarray)
Out[483]:
rec.array([(4.0, 6.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
In [484]: _.x
Out[484]: array([ 4.])
In [485]: points.sum(0).view(point_type)
Out[485]:
array([(9.0, 12.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
或者我可以从 point_type
开始,将其视为数学的 2d,然后再查看
pdt1=np.dtype((float, (2,)))
In [502]: points
Out[502]:
array([(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
In [503]: points.view(pdt1)
Out[503]:
array([[ 1., 2.],
[ 3., 4.],
[ 5., 6.]])
In [504]: points.view(pdt1).sum(0).view(point_type)
Out[504]:
array([(9.0, 12.0)],
dtype=[('x', '<f8'), ('y', '<f8')])
因此可以将数组作为 2d 和 recarray 查看和操作。为了漂亮或有用,它可能需要埋在用户定义的 class.
中从 recarray
class 抄袭想法的另一种选择。它的核心只是一个结构化数组,带有专门的 __getattribute__
(和 setattribute)方法。该方法首先尝试普通数组方法和属性(例如 x.shape
、x.sum
)。然后它尝试在定义的字段名中调整 attr
。
def __getattribute__(self, attr):
try:
return object.__getattribute__(self, attr)
except AttributeError: # attr must be a fieldname
pass
fielddict = ndarray.__getattribute__(self, 'dtype').fields
try:
res = fielddict[attr][:2]
except (TypeError, KeyError):
raise AttributeError("record array has no attribute %s" % attr)
return self.getfield(*res)
...
points.view(np.recarray).x
变为 points.getfield(*points.dtype.fields['x'])
.
另一种方法是借鉴 namedtuple
(/usr/lib/python3.4/collections/__init__.py
),并定义 x
和 y
属性,这将索引 [:,0]
和二维数组的 [:,1]
列。
将这些属性添加到 np.matrix
的子 class 可能是最简单的方法,让 class 确保大多数数学结果是二维的。