混合柱¶
astropy
表支持表中“mixin列”的概念,它允许集成适当的- Column
一个 Table
对象。这些mixin列对象不以任何方式转换,而是在本机使用。
可用的内置mixin列类有:
例子¶
例如,我们可以创建一个表并添加一个时间列:
>>> from astropy.table import Table
>>> from astropy.time import Time
>>> t = Table()
>>> t['index'] = [1, 2]
>>> t['time'] = Time(['2001-01-02T12:34:56', '2001-02-03T00:01:02'])
>>> print(t)
index time
----- -----------------------
1 2001-01-02T12:34:56.000
2 2001-02-03T00:01:02.000
重要的一点是 time
专栏是善意的 Time
对象:
>>> t['time']
<Time object: scale='utc' format='isot' value=['2001-01-02T12:34:56.000' '2001-02-03T00:01:02.000']>
>>> t['time'].mjd
array([51911.52425926, 51943.00071759])
数量和数量¶
本机处理的能力 Quantity
表中的对象使以自然和健壮的方式操作带有单位的表格数据更加方便。但是,这个特性引入了一个模糊性,因为带有单位的数据(例如,来自FITS二进制表)可以表示为 Column
用一个 unit
属性或作为 Quantity
对象。为了彻底解决这种模糊性, astropy
定义 Table
类称为 QTable
. 这个 QTable
类与 Table
除了那个 Quantity
是具有已定义单位的任何数据列的默认值。
如果你利用 Quantity
那么你的分析中的基础设施 QTable
是使用单位创建表的首选方法。如果您更多地使用表列单位作为描述性标签,那么 Table
类可能是最好的类。
例子¶
为了说明这些概念,我们首先创建一个标准 Table
在这里我们提供输入a Time
对象与A Quantity
对象的单位为 m / s
. 在这种情况下,数量转换为 Column
(它有一个 unit
属性,但不具有 Quantity
):
>>> import astropy.units as u
>>> t = Table()
>>> t['index'] = [1, 2]
>>> t['time'] = Time(['2001-01-02T12:34:56', '2001-02-03T00:01:02'])
>>> t['velocity'] = [3, 4] * u.m / u.s
>>> print(t)
index time velocity
m / s
----- ----------------------- --------
1 2001-01-02T12:34:56.000 3.0
2 2001-02-03T00:01:02.000 4.0
>>> type(t['velocity'])
<class 'astropy.table.column.Column'>
>>> t['velocity'].unit
Unit("m / s")
>>> (t['velocity'] ** 2).unit # WRONG because Column is not smart about unit
Unit("m / s")
所以让我们用数量表来做同样的事情 QTable
::
>>> from astropy.table import QTable
>>> qt = QTable()
>>> qt['index'] = [1, 2]
>>> qt['time'] = Time(['2001-01-02T12:34:56', '2001-02-03T00:01:02'])
>>> qt['velocity'] = [3, 4] * u.m / u.s
这个 velocity
列现在是 Quantity
并据此行事:
>>> type(qt['velocity'])
<class 'astropy.units.quantity.Quantity'>
>>> qt['velocity'].unit
Unit("m / s")
>>> (qt['velocity'] ** 2).unit # GOOD!
Unit("m2 / s2")
>>> qt2 = QTable(t)
>>> type(qt2['velocity'])
<class 'astropy.units.quantity.Quantity'>
>>> t2 = Table(qt2)
>>> type(t2['velocity'])
<class 'astropy.table.column.Column'>
备注
总结一下: only 两者之间的区别 QTable
和 Table
添加具有指定单位的列时的行为。与 QTable
这样的列总是转换为 Quantity
对象,然后添加到表中。同样,如果为现有单位指定了一个单位,则 Column
在一个 QTable
,然后将列转换为 Quantity
.
混合属性¶
常用的列属性 name
, dtype
, unit
, format
和 description
可通过 info
属性:
>>> qt['velocity'].info.name
'velocity'
这个 info
属性是一个关键的粘合剂,它允许非列对象的行为非常类似于列。
相同的 info
标准配置中也提供了属性 Column
物体。这些 info
像 t['a'].info.name
请直接联系 Column
属性(例如。, t['a'].name
)可以互换使用。同样的 Quantity
对象, info.dtype
属性引用本机 dtype
对象的属性。
备注
在编写处理可能是mixin列的列对象的通用代码时,必须 总是 使用 info
属性来访问列属性。
细节和注意事项¶
当mixin列是表的一部分时,大多数常用表操作的行为与预期一致。然而,目前的实施存在局限性。
添加或插入行
添加或插入行仅对可变(数据可以在内部更改)且具有 insert()
方法。 Quantity
和 Time
支持 insert()
但是,例如, SkyCoord
没有。如果试图将行插入到具有 SkyCoord
列,则会发生如下异常:
ValueError: Unable to insert row because of exception in column 'skycoord':
'SkyCoord' object has no attribute 'insert'
从行列表或dict列表初始化
这种初始化表的模式不适用于mixin列,因此以下两种情况都将失败:
>>> qt = QTable([{'a': 1 * u.m, 'b': 2},
... {'a': 2 * u.m, 'b': 3}])
Traceback (most recent call last):
...
TypeError: only dimensionless scalar quantities can be converted to Python scalars
>>> qt = QTable(rows=[[1 * u.m, 2],
... [2 * u.m, 3]])
Traceback (most recent call last):
...
TypeError: only dimensionless scalar quantities can be converted to Python scalars
问题在于知道是否以及如何将每个列的各个元素组合成适当的mixin列。当前代码使用 numpy
但不喜欢在字符串类型中对它执行mixor函数 Quantity
或 SkyCoord
.
Masking
Mixin列通常不支持屏蔽(除了 Time
),但对在屏蔽表中使用mixin的支持有限。在这种情况下a mask
属性指定给mixin列对象。这个 mask
是一个特殊对象,它是 False
对应于mixin数据形状。这个 mask
看起来很正常 numpy
数组,但如果 True
分配给任何元素。限制的后果在高级表操作中最为明显。
High-level table operations
下表总结了对包含mixin列的表的高级操作的支持:
操作 |
支持 |
---|---|
尚未实施,但没有根本限制。 |
|
可用于 |
|
当输出混合列支持屏蔽或不需要屏蔽时工作。 |
|
如果输出mixin列支持掩码或不需要掩码,则有效;键列必须是 |
|
尚未实现,使用分组操作。 |
ASCII表写入
具有mixin列的表可以使用 astropy.io.ascii
模块,但快速的基于C的编写器不可用。相反,将使用纯Python编写器。对于使用mixin列编写表,建议使用 'ecsv'
ASCII格式。这将完全序列化表数据和元数据,允许在读回表时进行完整的“往返”。看到了吗 ECSV格式 有关详细信息。
二进制表写入
从 `astropy
3.0中,包含mixin列的表可以使用FITS和HDF5格式以二进制格式写入文件。这些可以读回原稿 Table
包括mixin列和元数据。看到了吗 统一文件读写接口 有关详细信息。
Mixin协议¶
mixin列背后的一个关键思想是,可以使用任何满足指定协议的类。这意味着许多处理类数组数据的用户定义类对象可以在 Table
. 协议相对简洁,并且要求类的行为类似于 numpy
具有以下属性的数组:
包含类似数组的数据。
器具
__getitem__
支持将数据作为单个项、切片或索引数组访问获取。有一个
shape
属性。有一个
__len__
长度的方法。有一个
info
类描述符,它是astropy.utils.data_info.MixinInfo
班级。
这个 Example: ArrayWrapper 节显示了一个可以用作mixin列的类的最小工作示例。A pandas.Series 对象也可以用作mixin列。
mixin列的其他有趣的可能性包括:
作为其他列的函数动态计算的列(又称电子表格)。
列本身是
Table
(即嵌套表)。A proof of concept 可用。
new_like()方法¶
为了支持像 join
和 vstack
,mixin类必须提供 new_like()
方法在 info
类描述符。该功能的一个关键部分是确保适当地合并输入列元数据,并且列具有一致的属性,例如形状。
提供 new_like()
还必须实施 __setitem__
支持通过单个项、切片或索引数组进行设置。
这个 new_like
方法具有以下签名:
def new_like(self, cols, length, metadata_conflicts='warn', name=None):
"""
Return a new instance of this class which is consistent with the
input ``cols`` and has ``length`` rows.
This is intended for creating an empty column object whose elements can
be set in-place for table operations like join or vstack.
Parameters
----------
cols : list
List of input columns
length : int
Length of the output column object
metadata_conflicts : str ('warn'|'error'|'silent')
How to handle metadata conflicts
name : str
Output column name
Returns
-------
col : object
New instance of this class consistent with ``cols``
"""
可以在 ColumnInfo
和 QuantityInfo
类。
示例:ArrayWrapper¶
下面的代码列表显示了一个充当mixin列类的数据容器类的示例。这个类是一个 numpy
数组。它用于 astropy
mixin测试套件,作为mixin列完全兼容。
from astropy.utils.data_info import ParentDtypeInfo
class ArrayWrapper(object):
"""
Minimal mixin using a simple wrapper around a numpy array
"""
info = ParentDtypeInfo()
def __init__(self, data):
self.data = np.array(data)
if 'info' in getattr(data, '__dict__', ()):
self.info = data.info
def __getitem__(self, item):
if isinstance(item, (int, np.integer)):
out = self.data[item]
else:
out = self.__class__(self.data[item])
if 'info' in self.__dict__:
out.info = self.info
return out
def __setitem__(self, item, value):
self.data[item] = value
def __len__(self):
return len(self.data)
@property
def dtype(self):
return self.data.dtype
@property
def shape(self):
return self.data.shape
def __repr__(self):
return f"<{self.__class__.__name__} name='{self.info.name}' data={self.data}>"