如前所述,多场选择处于不断变化的状态。我最近更新到 1.14.2,行为又回到了 1.14.0 之前的状态。
In [114]: data = np.array([(1.0, 2.0, 0), (3.0, 4.0, 1)],
...: dtype=[('feature_1', float), ('feature_2', float), ('resul
...: t', int)])
...:
In [115]: data
Out[115]:
array([(1., 2., 0), (3., 4., 1)],
dtype=[('feature_1', '<f8'), ('feature_2', '<f8'), ('result', '<i8')])
In [116]: features = data[['feature_1', 'feature_2']]
In [117]: features
Out[117]:
array([(1., 2.), (3., 4.)],
dtype=[('feature_1', '<f8'), ('feature_2', '<f8')])
(我省略了额外的recarray
转换层。)
在 1.14.0 中,此 dtype 将包含一个offset
值,表明这features
是一个视图,而不是一个副本。
我可以在features
不更改的情况下更改值data
:
In [124]: features['feature_1']
Out[124]: array([1., 3.])
In [125]: features['feature_1'] = [4,5]
In [126]: features
Out[126]:
array([(4., 2.), (5., 4.)],
dtype=[('feature_1', '<f8'), ('feature_2', '<f8')])
In [127]: data
Out[127]:
array([(1., 2., 0), (3., 4., 1)],
dtype=[('feature_1', '<f8'), ('feature_2', '<f8'), ('result', '<i8')])
但是如果不深入研究开发讨论,我不能说长期解决方案是什么。理想情况下,它应该具有获取 a view
(维护到原始数据缓冲区的链接)和副本的能力,一个独立且可自由修改的数组。
我怀疑该copy
版本将遵循recfunctions
使用新 dtype 构造新数组,然后逐字段复制数据的做法。
In [132]: data.dtype.descr
Out[132]: [('feature_1', '<f8'), ('feature_2', '<f8'), ('result', '<i8')]
In [133]: dt = data.dtype.descr[:-1]
In [134]: dt
Out[134]: [('feature_1', '<f8'), ('feature_2', '<f8')]
In [135]: arr = np.zeros(data.shape, dtype=dt)
In [136]: arr
Out[136]:
array([(0., 0.), (0., 0.)],
dtype=[('feature_1', '<f8'), ('feature_2', '<f8')])
In [137]: for name in arr.dtype.fields:
...: arr[name] = data[name]
...:
In [138]: arr
Out[138]:
array([(1., 2.), (3., 4.)],
dtype=[('feature_1', '<f8'), ('feature_2', '<f8')])
或另一个recfunctions函数:
In [159]: rf.drop_fields(data, 'result')
Out[159]:
array([(1., 2.), (3., 4.)],
dtype=[('feature_1', '<f8'), ('feature_2', '<f8')])
recfunctions
具有可以复制复杂 dtypes 的代码,具有嵌套 dtypes 等的代码。但是对于像这样简单的一层 dtype,简单的字段名称迭代就足够了。
一般来说,结构化数组(和recarray)有很多记录和有限数量的字段。所以按名称复制字段是比较高效的。
In [150]: import numpy.lib.recfunctions as rf
In [154]: arr = np.zeros(data.shape, dtype=dt)
In [155]: rf.recursive_fill_fields(data, arr)
Out[155]:
array([(1., 2.), (3., 4.)],
dtype=[('feature_1', '<f8'), ('feature_2', '<f8')])
但请注意它的代码以:
output = np.empty(base.shape, dtype=newdtype)
output = recursive_fill_fields(base, output)
开发说明在某些时候提到了一个recfunctions.compress_fields
功能,但显然从未真正添加过。