假设我有一对看起来像这样的numpy数组X
和I
(X是2D,我是1D)
X I
-----------------
3.4 9.13 0
3.5 3.43 1
3.6 2.01 2
3.7 6.11 0
3.8 4.95 1
3.9 7.02 2
4.0 4.41 3
4.1 0.23 0
4.2 0.99 1
4.3 1.02 0
4.4 5.61 1
4.5 7.55 2
4.6 8.10 0
4.7 0.33 2
4.8 0.80 1
我想做两件事:
Y = indexby(X,I,I0)
:给定值I0,找到X中具有匹配值的行。例如,如果我是2,我想找到以下数组:
3.6 2.01
3.9 7.02
4.5 7.55
4.7 0.33
Y = indexby(X,I)
:返回包含所有可能键k
的字典,以便Y[k] == indexby(X,I,k)
。在我的示例数据中,这将产生以下结果:
Y[0] =
3.4 9.13
3.7 6.11
4.1 0.23
4.3 1.02
4.6 8.10
Y[1] =
3.5 3.43
3.8 4.95
4.2 0.99
4.4 5.61
4.8 0.80
Y[2] =
3.6 2.01
3.9 7.02
4.5 7.55
4.7 0.33
Y[3] =
4.0 4.41
是否有numpy函数执行此操作?我不知道该找什么,所以很难找到它们。
我知道我可以手动执行此操作,但出于性能原因,我想使用内置numpy函数,因为我的应用程序中的数组通常具有100,000到1,000,000范围内的行数。
答案 0 :(得分:4)
有一些更高级别的功能,但让我们看看如何使用库中最简单的东西来做,因为你每天都需要这些简单的功能。
>>> matches = (I == 2)
>>> matches
array([False, False, True, False, False, True, False, False, False,
False, False, True, False, True, False], dtype=bool)
>>> indices = np.nonzero(matches)
>>> indices
(array([ 2, 5, 11, 13]),)
>>> xvals = X[indices]
>>> xvals
array([[ 3.6 , 2.01],
[ 3.9 , 7.02],
[ 4.5 , 7.55],
[ 4.7 , 0.33]])
最后一步可能看起来令人困惑。有关详细信息,请参阅教程中的Indexing。
了解==
运算符和nonzero
的工作原理后,请查看与nonzero
相同的部分中的其他函数,您应该找到两种较短的方法来执行此操作。
答案 1 :(得分:2)
如果您想尝试pandas
,它在groupby
数据中非常强大。以下是如何实现您的需求:
In [34]: import numpy as np
In [35]: import pandas as pd
#I defined you X, I already
In [36]: X
Out[36]:
array([[ 3.4 , 9.13],
[ 3.5 , 3.43],
[ 3.6 , 2.01],
[ 3.7 , 6.11],
[ 3.8 , 4.95],
[ 3.9 , 7.02],
[ 4. , 4.41],
[ 4.1 , 0.23],
[ 4.2 , 0.99],
[ 4.3 , 1.02],
[ 4.4 , 5.61],
[ 4.5 , 7.55],
[ 4.6 , 8.1 ],
[ 4.7 , 0.33],
[ 4.8 , 0.8 ]])
In [37]: I
Out[37]: array([0, 1, 2, 0, 1, 2, 3, 0, 1, 0, 1, 2, 0, 2, 1], dtype=int64)
In [38]: dataframe=pd.DataFrame (data=X, index=I, columns=['X1','X2'])
In [39]: dataframe.index.name='I' #This is not necessary
In [40]: print dataframe
X1 X2
I
0 3.4 9.13
1 3.5 3.43
2 3.6 2.01
0 3.7 6.11
1 3.8 4.95
2 3.9 7.02
3 4.0 4.41
0 4.1 0.23
1 4.2 0.99
0 4.3 1.02
1 4.4 5.61
2 4.5 7.55
0 4.6 8.10
2 4.7 0.33
1 4.8 0.80
这将数据框定义为I
作为索引,X
作为数据。现在,如果您需要I=2
行,则可以执行
In [42]: print dataframe.ix[2]
X1 X2
I
2 3.6 2.01
2 3.9 7.02
2 4.5 7.55
2 4.7 0.33
如果要列出所有组:
In [43]: for i, grouped_data in dataframe.groupby(level='I'): #without level=, you can group by a regular column like X1
....: print i
....: print grouped_data
....:
0
X1 X2
I
0 3.4 9.13
0 3.7 6.11
0 4.1 0.23
0 4.3 1.02
0 4.6 8.10
1
X1 X2
I
1 3.5 3.43
1 3.8 4.95
1 4.2 0.99
1 4.4 5.61
1 4.8 0.80
2
X1 X2
I
2 3.6 2.01
2 3.9 7.02
2 4.5 7.55
2 4.7 0.33
3
X1 X2
I
3 4 4.41
如果您只想查看每个组的统计信息,可以执行
In [47]: print dataframe.groupby(level='I').sum() #try other funcs like mean, var, .
X1 X2
I
0 20.1 24.59
1 20.7 15.78
2 16.7 16.91
3 4.0 4.41
答案 2 :(得分:1)
首先,我将使用structured arrays展示一个不错的解决方案。链接的文档有很多关于索引,排序和创建它们的各种方法的好信息。
让我们定义您的数据的子集
import numpy as np
X = np.array( [[3.4,9.13], [3.5,3.43], [3.6,2.01], [3.7,6.11],
[3.8,4.95], [3.9,7.02], [4.0,4.41]] )
I = np.array( [0,1,2,0,1,2,3], dtype=np.int32 )
如果我们从这些数据中创建一个结构化数组(即结构数组),问题就很简单了,
sa = np.zeros( len(X), dtype=[('I',np.int64),('X',np.float64,(2))] )
在这里,我们制作了一个空的结构化数组。数组的每个元素是64位整数和64位浮点数的2元素数组。传递给dtype
的列表定义了结构,每个元组代表结构的一个组件。元组包含标签,类型和形状。形状部分是可选的,默认为标量条目。
接下来,我们用您的数据
填充结构化数组sa['I'] = I
sa['X'] = X
此时您可以访问类似的记录,
>>> sa['X'][sa['I']==2]
array([[ 3.6 , 2.01],
[ 3.9 , 7.02]])
在这里,我们要求所有的' X'记录并使用语句sa['I']==2
创建的bool数组为它们编制索引。然后可以使用理解构建您想要的词典,
d = { i:sa['X'][sa['I']==i] for i in np.unique(sa['I']) }
接下来是两个使用标准numpy数组的解决方案。第一个使用np.where
并使数组保持不变,另一个涉及对数组进行排序,这对于大I
来说应该更快。
np.where
使用np.where
并不是绝对必要的,因为数组可以使用下面I==I0
生成的bool数组进行索引,但在某些情况下将实际索引作为整数是有用的。
def indexby1( X,I,I0 ):
indx = np.where( I==I0 )
sub = X[indx[0],:]
return sub
def indexby2( X,I ):
d = {}
I0max = I.max()
for I0 in range(I0max+1):
d[I0] = indexby1( X, I, I0 )
return d
d = indexby2( X, I )
或者,您可以使用提到的排序解决方案,只返回块,
def order_arrays( X, I ):
indx = I.argsort()
I = I[indx]
X = [indx] # equivalent to X = X[indx,:]
return X, I
def indexby(X, I, I0=None):
if I0 == None:
d = {}
for I0 in range(I.max()+1):
d[I0] = indexby( X, I, I0 )
return d
else:
ii = I.searchsorted(I0)
ff = I.searchsorted(I0+1)
sub = X[ii:ff]
return sub
X,I = order_array( X, I )
d = indexby( X, I )
这里我将前面两个函数组合成一个递归函数,就像你在问题中描述了签名一样。这当然会修改原始数组。