【问题标题】:Build array from other array and table of values (Python)从其他数组和值表构建数组(Python)
【发布时间】:2015-08-11 08:10:31
【问题描述】:

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

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 的第三列中的任何值(c[k] for k= 1,2,... m),只要满足 a[k]

在我正在处理的实际案例中,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 ]

【问题讨论】:

  • 你为什么要zip([1,2, ..., n],[1,2, ..., m])?这似乎与您想象的不一样。
  • @user2357112:您确实是正确的,我已经更新了问题。谢谢。
  • 新版本看起来还是有问题。每个y[i] 值都会被一遍又一遍地覆盖。
  • @jorgehumberto posted solution 对你有用吗?
  • @Divakar:完美,谢谢!创建数组需要 3.5 秒(将 X 和 Y 扩展为 2D 数组时),而不是迭代所有元素时需要几分钟。

标签: arrays performance python-2.7 numpy


【解决方案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])

【讨论】:

    【解决方案2】:

    使用一维数组,还不错:

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

    如果xy 是高维的,那么你的A 矩阵也需要更大。不过,基本概念是一样的。

    【讨论】:

    • 对不起,你让我意识到解释不正确。 A 的长度为“m”,但 X 和 Y 的长度为“n”。 Y 可以在 A 的第三“列”中取任何值。我已更新问题以使其更清晰。
    猜你喜欢
    • 1970-01-01
    • 2019-12-20
    • 2016-11-05
    • 2012-10-08
    • 2023-01-17
    • 2016-04-04
    • 2015-09-30
    • 2016-11-07
    • 1970-01-01
    相关资源
    最近更新 更多