从其他数组和值表构建数组(Python)

时间:2015-05-28 17:11:31

标签: arrays performance python-2.7 numpy

我有一个值表,存储在列表列表中,如:

A = [   [a[1],b[1],c[1]],
        [a[2],b[2],c[2]],
        ...

        [a[m],b[m],c[m]]]

with
a[i] < b[1]
b[i] < a[i+1]
0 < c[i] < 1 

和一个numpy数组,如:

 X = [x[1], x[2], ..., x[n]]

我需要创建一个数组

 Y = [y[1], y[2], ..., y[n]]

其中Y的每个值都对应

for i in [1,2, ..., n]:
  for k in [1,2, ..., m]:
     if a[k] <  x[i] < b[k]:
         y[i] = c[k]
     else:
         y[i] = 1 

请注意X和Y的长度相同,但A完全不同。 Y可以取A的第三列中的任何值(对于k = 1,2,... m,c [k]),只要a [k] <1。 x [i]&lt;满足b [k](对于k = 1,2,... m和对于i = 1,2,... n)。

在我正在处理的实际案例中,n = 6789,m = 6172。

我可以使用嵌套的“for”循环进行验证,但它确实很慢。实现这一目标的最快方法是什么?如果X和Y在哪里有2D numpy数组呢?

示例数据:

a = [10, 20, 30, 40, 50, 60, 70, 80, 90]
b = [11, 21, 31, 41, 51, 61, 71, 81, 91]
c = [ 0.917,  0.572,  0.993 ,  0.131,  0.44, 0.252 ,  0.005,  0.375,  0.341]

A = A = [[d,e,f] for d,e,f in zip(a,b,c)]

X = [1, 4, 10.2, 20.5, 25, 32, 41.3, 50.5, 73]

预期成果:

Y = [1, 1, 0.993, 0.132, 1, 1, 1, 0.375, 1 ]

2 个答案:

答案 0 :(得分:1)

方法#1:使用与broadcasting的强力比较 -

import numpy as np

# Convert to numpy arrays
A_arr = np.array(A)
X_arr = np.array(X)

# Mask that represents "if a[k] <  x[i] < b[k]:" for all i,k
mask = (A_arr[:,None,0]<X_arr) & (X_arr<A_arr[:,None,1])

# Get indices where the mask has 1s, i.e. the conditionals were satisfied
_,C = np.where(mask)

# Setup output numpy array and set values in it from third column of A 
# that has conditionals satisfied for specific indices
Y = np.ones_like(X_arr)
Y[C] = A_arr[C,2]

方法#2:基于与np.searchsorted -

的分箱
import numpy as np

# Convert A to 2D numpy array
A_arr = np.asarray(A)

# Setup intervals for binning later on 
intv = A_arr[:,:2].ravel()

# Perform binning & get interval & grouped indices for each X 
intv_idx = np.searchsorted(intv, X, side='right')
grp_intv_idx = np.floor(intv_idx/2).astype(int)

# Get mask of valid indices, i.e. X elements are within grouped intervals
mask = np.fmod(intv_idx,2)==1

# Setup output array 
Y = np.ones(len(X))

# Extract col-3 elements with grouped indices and valid ones from mask
Y[mask] = A_arr[:,2][grp_intv_idx[mask]]

# Remove (set to 1's) elements that fall exactly on bin boundaries
Y[np.in1d(X,intv)] = 1

请注意,如果您需要输出作为列表,您可以将numpy数组转换为带有这样的调用的列表 - Y.tolist()

示例运行 -

In [480]: A
Out[480]: 
[[139.0, 355.0, 0.5047342078960846],
 [419.0, 476.0, 0.3593886192040009],
 [580.0, 733.0, 0.3137694021600973]]

In [481]: X
Out[481]: [555, 689, 387, 617, 151, 149, 452]

In [482]: Y
Out[482]: 
array([ 1.        ,  0.3137694 ,  1.        ,  0.3137694 ,  0.50473421,
        0.50473421,  0.35938862])

答案 1 :(得分:0)

使用1-d阵列时,它并不太糟糕:

a,b,c = np.array(A).T
mask = (a<x) & (x<b)
y = np.ones_like(x)
y[mask] = c[mask]

如果xy维度较高,那么您的A矩阵也需要更大。但基本概念的作用相同。