我有以下结构化数组:
import numpy as np
x = np.rec.array([(22,2,200.,2000.), (44,2,400.,4000.), (55,5,500.,5000.), (33,3,400.,3000.)],
dtype={'names':['subcase','id', 'vonmises','maxprincipal'], 'formats':['i4','i4','f4','f4']})
我正在尝试为每个id获取最大vonmises。
例如,id 2的最大vonmises将为400.我确实需要相应的子shell和maxprincipal。
这是我到目前为止所做的:
print repr(x[['subcase','id','vonmises']][(x['id']==2) & (x['vonmises']==max(x['vonmises'][x['id']==2]))])
这是输出:
array([(44, 2, 400.0)],
dtype=(numpy.record, [('subcase', '<i4'), ('id', '<i4'), ('vonmises', '<f4')]))
我现在遇到的问题是我希望这适用于数组中的所有ID,而不仅仅是id = 2.
即。想获得以下输出:
array([(44, 2, 400.0),(55, 5, 500.0),(33, 3, 400.0)],
dtype=(numpy.record, [('subcase', '<i4'), ('id', '<i4'), ('vonmises', '<f4')]))
有没有一种很好的方法可以在不指定每个ID的情况下完成此操作?
答案 0 :(得分:2)
我不知道你为什么使用这种格式,但这里有pandas
import pandas as pd
df = pd.DataFrame(x)
df_ = df.groupby('id')['vonmises'].max().reset_index()
In [213]: df_.merge(df, on=['id','vonmises'])[['id','vonmises','subcase']]
Out[213]:
array([[ 2., 400., 44.],
[ 3., 400., 33.],
[ 5., 500., 55.]], dtype=float32)
答案 1 :(得分:2)
以下是使用np.sort
(或argsort
)后跟itertools.groupby
的方法。但是这种分组工具会产生一个发电机发电机,这种发电机使用起来比较麻烦。
In [29]: x = np.rec.array([(22,2,200.,2000.), (44,2,400.,4000.), (55,5,500.,5000.), (33,3,400.,3000.)],
dtype={'names':['subcase','id', 'vonmises','maxprincipal'], 'formats':['i4','i4','f4','f4']})
In [30]: ind=x.argsort(order=['id','vonmises'])
In [31]: ind
Out[31]:
rec.array([0, 1, 3, 2],
dtype=int32)
In [32]: x[ind]
Out[32]:
rec.array([(22, 2, 200.0, 2000.0), (44, 2, 400.0, 4000.0), (33, 3, 400.0, 3000.0),
(55, 5, 500.0, 5000.0)],
dtype=[('subcase', '<i4'), ('id', '<i4'), ('vonmises', '<f4'), ('maxprincipal', '<f4')])
In [33]: import itertools
In [34]: [list(v) for k,v in itertools.groupby(x[ind],lambda i:i['id'])]
Out[34]:
[[(22, 2, 200.0, 2000.0), (44, 2, 400.0, 4000.0)],
[(33, 3, 400.0, 3000.0)],
[(55, 5, 500.0, 5000.0)]]
然后我们必须获取每个组的最后一个(或第一个为最小值)记录,然后重新构建recarray
。
In [39]: mx=[list(v)[-1] for k,v in itertools.groupby(x[ind],lambda i:i['id'])]
In [43]: np.rec.fromrecords(mx,dtype=x.dtype)
Out[43]:
rec.array([(44, 2, 400.0, 4000.0), (33, 3, 400.0, 3000.0), (55, 5, 500.0, 5000.0)],
dtype=[('subcase', '<i4'), ('id', '<i4'), ('vonmises', '<f4'), ('maxprincipal', '<f4')])
mx
的元素为np.record
且dtype
正确,但mx
本身就是一个列表。
或紧凑地:
g=itertools.groupby(np.sort(x,order=['id','vonmises']), lambda i:i['id'])
np.rec.fromrecords([list(v)[-1] for k,v in g], dtype=x.dtype)
答案 2 :(得分:1)
这是一种没有groupby的方法:
# sort as desired
x.sort(order=['id','vonmises'])
# keep the first element, and every element with a different id to the one before it
keep = np.empty(x.shape, dtype=np.bool)
keep[0] = True
keep[1:] = x[:-1].id != x[1:].id
x_filt = x[keep]
给出了:
rec.array([(22, 2, 200.0, 2000.0), (33, 3, 400.0, 3000.0), (55, 5, 500.0, 5000.0)],
dtype=[('subcase', '<i4'), ('id', '<i4'), ('vonmises', '<f4'), ('maxprincipal', '<f4')])
答案 3 :(得分:1)
使用numpy_indexed包,这将是一个简单的单行:
import numpy_indexed as npi
ids, maxvonmises = npi.group_by(x.id).max(x.vonmises)
可能与大熊猫相似,但更具可读性,无需根据手头的问题调整数据格式。