使用索引值从numpy数组中选择项目

时间:2014-07-25 23:03:29

标签: python arrays numpy

假设我有一对看起来像这样的numpy数组XI(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

我想做两件事:

  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  
    
  2. 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
    
  3. 是否有numpy函数执行此操作?我不知道该找什么,所以很难找到它们。

    我知道我可以手动执行此操作,但出于性能原因,我想使用内置numpy函数,因为我的应用程序中的数组通常具有100,000到1,000,000范围内的行数。

3 个答案:

答案 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 )

这里我将前面两个函数组合成一个递归函数,就像你在问题中描述了签名一样。这当然会修改原始数组。