从一个有4个字段的结构化numpy数组开始,我试图返回一个数组,其中只有最新的日期,按ID,包含相同的4个字段。我发现使用itertools.groupby
的解决方案几乎可以在这里工作:
Numpy Mean Structured Array
问题是当你有4个字段而不是2时我不明白如何调整它。我希望得到整个'行',但只有每个ID的最新日期的行。我知道使用pandas这种事情更简单,但这只是一个较大进程的一小部分,而且我不能将pandas添加为依赖项。
data = np.array([('2005-02-01', 1, 3, 8),
('2005-02-02', 1, 4, 9),
('2005-02-01', 2, 5, 10),
('2005-02-02', 2, 6, 11),
('2005-02-03', 2, 7, 12)],
dtype=[('dt', 'datetime64[D]'), ('ID', '<i4'), ('f3', '<i4'),
('f4', '<i4')])
对于这个示例数组,我想要的输出是:
np.array([(datetime.date(2005, 2, 2), 1, 4, 9),
(datetime.date(2005, 2, 3), 2, 7, 12)],
dtype=[('dt', '<M8[D]'), ('ID', '<i4'), ('f3', '<i4'), ('f4', '<i4')])
这是我尝试过的:
latest = np.array([(k, np.array(list(g), dtype=data.dtype).view(np.recarray)
['dt'].argmax()) for k, g in
groupby(np.sort(data, order='ID').view(np.recarray),
itemgetter('ID'))], dtype=data.dtype)
我收到此错误:
ValueError: size of tuple must match number of fields.
我认为这是因为元组有2个字段,但数组有4个。当我从数组中删除'f3'
和'f4'
时,它可以正常工作。
如何让它返回所有4个字段?
答案 0 :(得分:0)
让我们通过剥离一层来弄清楚你的错误在哪里:
In [38]: from operator import itemgetter
In [39]: from itertools import groupby
In [41]: [(k, np.array(list(g), dtype=data.dtype).view(np.recarray)
['dt'].argmax()) for k, g in
groupby(np.sort(data, order='ID').view(np.recarray),
itemgetter('ID'))]
Out[41]: [(1, 1), (2, 2)]
这个元组列表应该代表什么?它显然不是来自data
的行。由于每个元组只有2个项目,因此无法映射到data.dtype
数组。因此价值错误。
稍微讨论一下后,我认为:[(1, 1), (2, 2)]
表示对于ID==1
,使用该组中的[1]
项;对于ID==2
,请使用该组中的[2]
项。
[(datetime.date(2005, 2, 2), 1, 4, 9),
(datetime.date(2005, 2, 3), 2, 7, 12)]
您已找到最长日期,但必须将其转换为data
中的任一索引,或从这些组中选择这些项目。
In [91]: groups=groupby(np.sort(data, order='ID').itemgetter('ID'))
# don't need recarray
In [92]: G = [(k,list(g)) for k,g in groups]
In [93]: G
Out[93]:
[(1,
[(datetime.date(2005, 2, 1), 1, 3, 8),
(datetime.date(2005, 2, 2), 1, 4, 9)]),
(2,
[(datetime.date(2005, 2, 1), 2, 5, 10),
(datetime.date(2005, 2, 2), 2, 6, 11),
(datetime.date(2005, 2, 3), 2, 7, 12)])]
In [107]: I=[(1,1), (2,2)]
In [108]: [g[1][i[1]] for g,i in zip(G,I)]
Out[108]: [(datetime.date(2005, 2, 2), 1, 4, 9), (datetime.date(2005, 2, 3), 2, 7, 12)]
好的,来自G
的选择很笨拙,但这是一个开始。
如果我定义一个简单的函数来从组中提取最新日期的记录,那么处理就会简单得多。
def maxdate_record(agroup):
an_array = np.array(list(agroup))
i = np.argmax(an_array['dt'])
return an_array[i]
groups = groupby(np.sort(data, order='ID'),itemgetter('ID'))
np.array([maxdate_record(g) for k,g in groups])
制造
array([(datetime.date(2005, 2, 2), 1, 4, 9),
(datetime.date(2005, 2, 3), 2, 7, 12)],
dtype=[('dt', '<M8[D]'), ('ID', '<i4'), ('f3', '<i4'), ('f4', '<i4')])
当我将记录列表转换为数组时,我不需要指定dtype
,因为记录有自己的dtype。