修改表#
中的数据值 Table
对象的修改方式与 numpy
structured arrays 通过访问数据的列或行并适当地赋值。提供的一个关键增强功能 Table
类是修改表结构的能力:您可以添加或删除列,以及添加新的数据行。
快速概述#
下面的代码显示了修改表及其数据的基础知识。
实例#
做一张桌子 ::
>>> from astropy.table import Table
>>> import numpy as np
>>> arr = np.arange(15).reshape(5, 3)
>>> t = Table(arr, names=('a', 'b', 'c'), meta={'keywords': {'key1': 'val1'}})
修改数据值 ::
>>> t['a'][:] = [1, -2, 3, -4, 5] # Set all values of column 'a'
>>> t['a'][2] = 30 # Set row 2 of column 'a'
>>> t[1] = (8, 9, 10) # Set all values of row 1
>>> t[1]['b'] = -9 # Set column 'b' of row 1
>>> t[0:3]['c'] = 100 # Set column 'c' of rows 0, 1, 2
请注意 table[row][column]
作业不适用于 numpy
“花哨” row
索引(在这种情况下 table[row]
将是一种 copy 而不是一个 view )。《花哨》 numpy
指数包括 list
, numpy.ndarray
,或 tuple
的 numpy.ndarray
(例如,从 numpy.where()
):
>>> t[[1, 2]]['a'] = [3., 5.] # doesn't change table t
>>> t[np.array([1, 2])]['a'] = [3., 5.] # doesn't change table t
>>> t[np.where(t['a'] > 3)]['a'] = 3. # doesn't change table t
而是使用 table[column][row]
顺序:
>>> t['a'][[1, 2]] = [3., 5.]
>>> t['a'][np.array([1, 2])] = [3., 5.]
>>> t['a'][np.where(t['a'] > 3)] = 3.
也可以使用修改数据列 unit
以一种遵循 Quantity
通过使用 quantity
属性:
>>> from astropy import units as u
>>> tu = Table([[1, 2.5]], names=('a',))
>>> tu['a'].unit = u.m
>>> tu['a'].quantity[:] = [1, 2] * u.km
>>> tu['a']
<Column name='a' dtype='float64' unit='m' length=2>
1000.0
2000.0
添加一个或多个列
可以使用类似于将键-值对添加到 dict
。右侧的值可以是 list
或 numpy.ndarray
正确的大小,或将为 broadcast **
>>> t['d1'] = np.arange(5)
>>> t['d2'] = [1, 2, 3, 4, 5]
>>> t['d3'] = 6 # all 5 rows set to 6
要获得更明确的控制,请使用 add_column()
和 add_columns()
方法可用于向表中添加一列或多列。在这两种情况下,新列(S)都可以指定为 list
, numpy.ndarray
, Column
, MaskedColumn
,或标量::
>>> from astropy.table import Column
>>> t.add_column(np.arange(5), name='aa', index=0) # Insert before first table column
>>> t.add_column(1.0, name='bb') # Add column of all 1.0 to end of table
>>> c = Column(np.arange(5), name='e')
>>> t.add_column(c, index=0) # Add Column using the existing column name 'e'
>>> t.add_columns([[1, 2, 3, 4, 5], ['v', 'w', 'x', 'y', 'z']], names=['h', 'i'])
最后,还可以从添加列 Quantity
对象,这会自动设置 unit
属性(但您可能会发现添加一个 Quantity
到一个 QTable
相反,请参见 数量和数量 有关详情):
>>> from astropy import units as u
>>> t['d'] = np.arange(1., 6.) * u.m
>>> t['d']
<Column name='d' dtype='float64' unit='m' length=5>
1.0
2.0
3.0
4.0
5.0
删除列
要从表中删除列,请执行以下操作:
>>> t.remove_column('d1')
>>> t.remove_columns(['aa', 'd2', 'e'])
>>> del t['d3']
>>> del t['h', 'i']
>>> t.keep_columns(['a', 'b'])
替换列
通过将列设置为可用于初始化表列的任何对象(例如, list
或 numpy.ndarray
)。例如,您可以更改 a
列自 int
至 float
使用::
>>> t['a'] = t['a'].astype(float)
如果右侧的值不是列状的,则使用 broadcasting 将完成,例如::
>>> t['a'] = 1 # Internally does t['a'][:] = 1
Perform a dictionary-style update
可以执行字典样式的更新,将新列添加到表中并替换现有列:
>>> t1 = Table({'name': ['foo', 'bar'], 'val': [0., 0.]}, meta={'n': 2})
>>> t2 = Table({'val': [1., 2.], 'val2': [10., 10.]}, meta={'id': 0})
>>> t1 |= t2
>>> t1
<Table length=2>
name val val2
str3 float64 float64
---- ------- -------
foo 1.0 10.0
bar 2.0 10.0
使用时 |=
,则另一个对象不需要是 Table
,它可以是任何可以用来 构造表 具有兼容的行数::
>>> t1 = Table({'name': ['foo', 'bar'], 'val': [0., 0.]}, meta={'n': 2})
>>> d = dict({'val': [1., 2.], 'val2': [10., 10.]})
>>> t1 |= d
>>> t1
<Table length=2>
name val val2
str3 float64 float64
---- ------- -------
foo 1.0 10.0
bar 2.0 10.0
也可以使用 |
用于合并多个 Table
实例添加到新表中:
>>> from astropy.table import QTable
>>> t1 = Table({'name': ['foo', 'bar'], 'val': [0., 0.]}, meta={'n': 2})
>>> t2 = QTable({'val': [1., 2.], 'val2': [10., 10.]}, meta={'id': 0})
>>> t3 = t1 | t2 # Create a new table as result of update
>>> t3
<Table length=2>
name val val2
str3 float64 float64
---- ------- -------
foo 1.0 10.0
bar 2.0 10.0
|
和 |=
也默默地照顾着 合并元数据 **
>>> t3.meta
{'n': 2, 'id': 0}
更新后的 Table
将会是原件的复制品。如果您需要它们作为参考,您可以使用 update()
方法: copy=False
,见 复制与引用 了解更多细节。
Ensure the existence of a column
Table
有一个 setdefault()
方法,它类似于 dict.setdefault()
。如果表中不存在具有给定名称的列,它会将该列添加到表中。将验证传递给该方法的默认值,并在必要时进行转换。无论采用哪种方式,都会返回表中的(可能是刚刚插入的)列::
>>> t0 = Table({"a": ["Ham", "Spam"]})
>>> t0
<Table length=2>
a
str4
----
Ham
Spam
>>> t0.setdefault("a", ["Breakfast"]) # Existing column
<Column name='a' dtype='str4' length=2>
Ham
Spam
>>> t0.setdefault("approved", False) # New column
<Column name='approved' dtype='bool' length=2>
False
False
>>> t0
<Table length=2>
a approved
str4 bool
---- --------
Ham False
Spam False
重命名列
要重命名列:
>>> t.rename_column('a', 'a_new')
>>> t['b'].name = 'b_new'
添加一行数据
添加行:
>>> t.add_row([-8, -9])
删除行
删除行:
>>> t.remove_row(0)
>>> t.remove_rows(slice(4, 5))
>>> t.remove_rows([1, 2])
按一列或多列排序
要对列排序:
>>> t.sort('b_new')
>>> t.sort(['a_new', 'b_new'])
反转表格行
要反转表行顺序,请执行以下操作:
>>> t.reverse()
修改元数据
要修改元数据:
>>> t.meta['key'] = 'value'
选择或重新排序列
可以创建包含列子集或重新排序的列列表的新表,如下例所示:
>>> t = Table(arr, names=('a', 'b', 'c'))
>>> t_acb = t['a', 'c', 'b']
另一种方法是提供一个列表或元组作为项,如下所示:
>>> new_order = ['a', 'c', 'b'] # List or tuple
>>> t_acb = t[new_order]
告诫#
修改表数据和属性是相当明确的,但是要记住的一点是添加一行 may 在表数据的内存中需要一个新副本。这取决于Python对象在内存中的详细布局,无法可靠地控制。在某些情况下,可以在不到O(N**2)的时间内逐行构建一个表,但不能指望它。
另一个要记住的微妙之处是,在某些情况下,操作的返回值会导致内存中的新表,而在其他情况下,它会导致现有表数据的视图。例如,想象一下使用列选择设置两个表元素 t['a', 'c']
结合行索引选择:
>>> t = Table([[1, 2], [3, 4], [5, 6]], names=('a', 'b', 'c'))
>>> t['a', 'c'][1] = (100, 100)
>>> print(t)
a b c
--- --- ---
1 3 5
2 4 6
这可能令人惊讶,因为数据值没有改变,也没有错误。事实上,事情是这样的 t['a', 'c']
在内存中创建了一个新的临时表作为 copy 然后更新副本的第一行。原来的 t
表不受影响,新的临时表在语句完成后消失。要点是注意如何一步一步地执行某些操作。
就地更新与替换列更新#
考虑以下代码片段:
>>> t = Table([[1, 2, 3]], names=['a'])
>>> t['a'] = [10.5, 20.5, 30.5]
有几种方法可以解决这个问题。它可以就地更新现有的数组值(截断为整数),也可以根据提供的数据值用新列替换整个列。
答案是 astropy
上面显示的操作执行的是 complete replacement 列对象的。在本例中,它通过内部调用创建一个具有浮点值的新列对象 t.replace_column('a', [10.5, 20.5, 30.5])
。通常情况下,此行为与Python和 pandas 行为。
Forcing in-place update
可以强制对列进行就地更新,如下所示:
t[colname][:] = value
找出问题的根源
为了找到与替换列相关的潜在问题,可以使用以下选项 astropy.table.conf.replace_warnings
在 配置系统 (astropy.config ) 。它控制在某些情况下替换表列时发出的一组警告。此选项必须设置为包含零个或多个以下字符串值的列表:
always
:方法每次替换列时都会打印警告
__setitem__()
语法(即,t['a'] = new_col
)。slice
:当一列显示为
slice
父列的属性被替换。refcount
:当列的Python引用计数更改时打印警告。这表示存在一个过时的对象,该对象可能会在代码的其他地方使用,并产生意外的结果。
attributes
:如果任何标准列属性发生更改,则打印警告。
的默认值 table.conf.replace_warnings
选项是 []
(无警告)。