Arrays 针对唯一值的高效数据筛选(Python)
我有一个由(X,Y,Z,a)值组成的二维Numpy数组,其中(X,Y,Z)是三维空间中的笛卡尔坐标,a是该位置的某个值。例如Arrays 针对唯一值的高效数据筛选(Python),arrays,python-2.7,numpy,unique,Arrays,Python 2.7,Numpy,Unique,我有一个由(X,Y,Z,a)值组成的二维Numpy数组,其中(X,Y,Z)是三维空间中的笛卡尔坐标,a是该位置的某个值。例如 __X__|__Y__|__Z__|__A_ 13 | 7 | 21 | 1.5 9 | 2 | 7 | 0.5 15 | 3 | 9 | 1.1 13 | 7 | 21 | 0.9 13 | 7 | 21 | 1.7 15 | 3 | 9 | 1.1 有没有一种有效的方法可以找到(X,Y)的所有唯一组
__X__|__Y__|__Z__|__A_
13 | 7 | 21 | 1.5
9 | 2 | 7 | 0.5
15 | 3 | 9 | 1.1
13 | 7 | 21 | 0.9
13 | 7 | 21 | 1.7
15 | 3 | 9 | 1.1
有没有一种有效的方法可以找到(X,Y)的所有唯一组合并添加它们的值?例如,(13,7)的总数将是(1.5+0.9+1.7)或4.1。
scipy。稀疏矩阵采用此类信息,但仅用于二维
sparse.coo_matrix((data, (row, col)))
其中行
和列
是类似于X
、Y
和Z
的索引。它是重复的
实现这一点的第一步是对索引进行词法排序。这使得具有匹配坐标的点彼此相邻
实际上,分组和求和是在编译代码中完成的。在numpy
术语中,这样做的部分困难在于每组中的元素数量可变。有些是唯一的,其他可能有3个或更多
Pythonitertools
有一个groupby
工具。熊猫还有分组功能。我还可以想象使用default\u dict
对值进行分组和求和
ufunc
reduceat
也可以工作,尽管它在1d中比在2或3中更容易使用
如果忽略Z
,则稀疏coo_矩阵
方法可能最简单
In [2]: X=np.array([13,9,15,13,13,15])
In [3]: Y=np.array([7,2,3,7,7,3])
In [4]: A=np.array([1.5,0.5,1.1,0.9,1.7,1.1])
In [5]: M=sparse.coo_matrix((A,(X,Y)))
In [15]: M.sum_duplicates()
In [16]: M.data
Out[16]: array([ 0.5, 2.2, 4.1])
In [17]: M.row
Out[17]: array([ 9, 15, 13])
In [18]: M.col
Out[18]: array([2, 3, 7])
In [19]: M
Out[19]:
<16x8 sparse matrix of type '<class 'numpy.float64'>'
with 3 stored elements in COOrdinate format>
当按这种方式排序时,Z
坐标是“冗余的”,至少在这个目的上是这样的
使用reduceat
对组进行求和:
In [40]: np.add.reduceat(A[idx],[0,1,3])
Out[40]: array([ 0.5, 2.2, 4.1])
(目前我只是浏览了[0,1,3]列表)方法#1
获取每一行作为视图,从而将每一行转换为标量,然后使用np.unique
将每一行标记为从(0……n)开始的最小标量,使用
n作为基于唯一性的唯一标量的数量,最后使用
np.bincount`根据先前获得的唯一标量对最后一列进行求和
下面是实现-
def get_row_view(a):
void_dt = np.dtype((np.void, a.dtype.itemsize * np.prod(a.shape[1:])))
a = np.ascontiguousarray(a)
return a.reshape(a.shape[0], -1).view(void_dt).ravel()
def groupby_cols_view(x):
a = x[:,:2].astype(int)
a1D = get_row_view(a)
_, indx, IDs = np.unique(a1D, return_index=1, return_inverse=1)
return np.c_[x[indx,:2],np.bincount(IDs, x[:,-1])]
def groupby_cols_linearindex(x):
a = x[:,:2].astype(int)
a1D = a[:,0] + a[:,1]*(a[:,0].max() - a[:,1].min() + 1)
_, indx, IDs = np.unique(a1D, return_index=1, return_inverse=1)
return np.c_[x[indx,:2],np.bincount(IDs, x[:,-1])]
方法#2
与方法#1相同,但不是使用视图
,而是为每行生成等效的线性索引,从而将每行减少为标量。工作流的其余部分与第一种方法相同
实施-
def get_row_view(a):
void_dt = np.dtype((np.void, a.dtype.itemsize * np.prod(a.shape[1:])))
a = np.ascontiguousarray(a)
return a.reshape(a.shape[0], -1).view(void_dt).ravel()
def groupby_cols_view(x):
a = x[:,:2].astype(int)
a1D = get_row_view(a)
_, indx, IDs = np.unique(a1D, return_index=1, return_inverse=1)
return np.c_[x[indx,:2],np.bincount(IDs, x[:,-1])]
def groupby_cols_linearindex(x):
a = x[:,:2].astype(int)
a1D = a[:,0] + a[:,1]*(a[:,0].max() - a[:,1].min() + 1)
_, indx, IDs = np.unique(a1D, return_index=1, return_inverse=1)
return np.c_[x[indx,:2],np.bincount(IDs, x[:,-1])]
样本运行
In [80]: data
Out[80]:
array([[ 2. , 5. , 1. , 0.40756048],
[ 3. , 4. , 6. , 0.78945661],
[ 1. , 3. , 0. , 0.03943097],
[ 2. , 5. , 7. , 0.43663582],
[ 4. , 5. , 0. , 0.14919507],
[ 1. , 3. , 3. , 0.03680583],
[ 1. , 4. , 8. , 0.36504428],
[ 3. , 4. , 2. , 0.8598825 ]])
In [81]: groupby_cols_view(data)
Out[81]:
array([[ 1. , 3. , 0.0762368 ],
[ 1. , 4. , 0.36504428],
[ 2. , 5. , 0.8441963 ],
[ 3. , 4. , 1.64933911],
[ 4. , 5. , 0.14919507]])
In [82]: groupby_cols_linearindex(data)
Out[82]:
array([[ 1. , 3. , 0.0762368 ],
[ 1. , 4. , 0.36504428],
[ 3. , 4. , 1.64933911],
[ 2. , 5. , 0.8441963 ],
[ 4. , 5. , 0.14919507]])
这些很好,谢谢!我认为lexsort
是我计划“艰难地”做的事情——我不知道它已经有了一个函数,因此我提出了问题。我喜欢将数据保留在lexsort
中的方式,因此我将继续。我实际上使用了您的答案——添加“示例运行”非常有用,可以再次检查函数。