我有一个numpy
结构化阵列
import numpy as np
arr1 = (np.array([2, 5, 8, 3, 10], dtype=np.int64),np.array([10, 10, 10, 8, 3], dtype=np.int64))
arr1_x = arr1[0]
arr1_y = arr1[1]
arr1_struct = np.empty(arr1_x.shape[0], dtype=[('x', int), ('y', int)])
arr1_struct["x"] = arr1_x
arr1_struct["y"] = arr1_y
正如您所看到的,在上面的结构化数组中,我有x和y值。我需要做以下
- 检查是否存在多个相同的y值
- 如果有,那么我只需要为y值保留一个x,y
- 要保留的x值需要是与所讨论的y的值相对应的几个x数值中最小的1x
- x,y对是唯一的,不重复
- 要保留的x值需要是与所讨论的y的值相对应的几个x数值中最小的1x
在上面的例子中,我需要保持:
- x=2和y=10(从三个y=10值中选择(
- x=3和y=8
- x=10和y=3
以下内容需要丢弃:
- x=5和y=10
- x=8和y=10
在numpy
中有什么好的方法可以实现这一点吗?
首先,让我们稍微简化一下创建灰泥阵列的方式,没有其他原因,因为它正在磨我的齿轮:
data = np.stack(([2, 5, 8, 3, 10], [10, 10, 10, 8, 3]), axis=-1)
data = data.view(np.dtype([('x', int), ('y', int)])).ravel()
对数据进行排序并找到y
的唯一值后,可以将np.minimum.reduceat
应用于x
:的结果段
data = data[np.argsort(data['y'])]
splits = np.r_[0, np.flatnonzero(np.diff(data['y'])) + 1]
x = np.minimum.reduceat(data['x'], splits)
y = data['y'][splits]
现在,您可以像以前一样重新创建阵列:
result = np.stack((x, y), axis=-1).view(data.dtype).ravel()
这就是np.unique
和pd.DataFrame.groupby
的工作原理。好的方面是,这种方法对重复配对不敏感。
另一种方法是使用np.lexsort
,它可以同时对两列进行排序,从而使每个段的第一个元素最小:
data = data[np.lexsort((data['x'], data['y']))]
splits = np.r_[0, np.flatnonzero(np.diff(data['y'])) + 1]
result = data[splits]
这种方法比较干净,因为它允许您直接对数据进行索引。
也可以使用return_index=True
将np.diff
计算替换为np.unique
。这稍微贵一点,因为它对数组进行了两次排序:
data = data[np.lexsort((data['x'], data['y']))]
result = data[np.unique(data['y'], return_index=True)[1]]