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

2024-10-03 13:29:23 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一对numpy数组XI,看起来像这样(X是2D,I是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中I中具有匹配值的行。例如,如果I为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
    

有没有numpy函数可以做到这一点?我不知道该找什么,所以很难找到。你知道吗

我知道我可以手动执行此操作,但出于性能原因,我希望使用内置numpy函数,因为我的应用程序中的数组的行数通常在100000-1000000范围内。你知道吗


Tags: 数据函数numpy应用程序示例字典原因数组
3条回答

如果您想尝试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

首先,我将使用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数组对数组进行索引,但是在某些情况下,将实际索引作为int是有用的。你知道吗

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 )

在这里,我将前面的两个函数合并为一个递归函数,正如您在问题中描述的签名一样。这当然会修改原始数组。你知道吗

有一些更高级的函数,但是让我们看看如何使用库中最简单的东西来实现,因为您每天都需要这些简单的函数。你知道吗

>>> 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相同部分中的其他函数,您应该找到两种较短的方法来实现这一点。你知道吗

相关问题 更多 >