【问题标题】:Indexing a numpy array with a arrays用数组索引 numpy 数组
【发布时间】:2021-04-17 22:44:43
【问题描述】:

我正在尝试将采用变量number 定义的 n 个索引进行计算的 vanilla python 标准偏差函数转换为 numpy 形式。但是 numpy 代码有问题,这就是说 only integer scalar arrays can be converted to a scalar index 有什么办法可以通过这个。

变量

import numpy as np
number = 5
list_= np.array([457.334015,424.440002,394.795990,408.903992,398.821014,402.152008,435.790985,423.204987,411.574005,
404.424988,399.519989,377.181000,375.467010,386.944000,383.614990,375.071991,359.511993,328.865997,
320.510010,330.079010,336.187012,352.940002,365.026001,361.562012,362.299011,378.549011,390.414001,
400.869995,394.773010,382.556000])

香草蟒

std= np.array([list_[i:i+number].std() for i in range(0, len(list_)-number)])

Numpy 表单

counter = np.arange(0, len(list_)-number, 1)
std = list_[counter:counter+number].std()

【问题讨论】:

  • 您不能使用numpy 数组(arange 的结果)作为切片的开始或停止。 arr[1:10] 可以,arr[np.array([1,2,3]: np.array([4,5,6]) 不行!你希望它会产生什么?

标签: python list function numpy indexing


【解决方案1】:
In [46]: std= np.array([arr[i:i+number].std() for i in range(0, len(arr)-number)
    ...: ])
In [47]: std
Out[47]: 
array([22.67653383, 10.3940773 , 14.60076482, 13.82801944, 13.68038469,
       12.54834004, 13.13574418, 15.24698722, 14.65383773, 11.62092989,
        8.57331689,  4.76392583,  9.49404494, 21.20874383, 24.91417226,
       20.84991841, 13.22152789, 10.83343482, 16.01294245, 13.80007894,
       10.51866421,  8.29287433, 11.24933733, 15.43661128, 13.65945978])

我们可以将std 移出循环。制作windows 的二维数组,并将stdaxis 一起应用:

In [48]: np.array([arr[i:i+number] for i in range(0, len(arr)-number)]).std(axis
    ...: =1)
Out[48]: 
array([22.67653383, 10.3940773 , 14.60076482, 13.82801944, 13.68038469,
       12.54834004, 13.13574418, 15.24698722, 14.65383773, 11.62092989,
        8.57331689,  4.76392583,  9.49404494, 21.20874383, 24.91417226,
       20.84991841, 13.22152789, 10.83343482, 16.01294245, 13.80007894,
       10.51866421,  8.29287433, 11.24933733, 15.43661128, 13.65945978])

我们还可以生成带有索引的窗口。一个方便的方法是使用linspace

In [63]: idx = np.arange(0,len(arr)-number)
In [64]: idx = np.linspace(idx,idx+number,number, endpoint=False,dtype=int)
In [65]: idx
Out[65]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
        16, 17, 18, 19, 20, 21, 22, 23, 24],
         ...
       [ 4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
        20, 21, 22, 23, 24, 25, 26, 27, 28]])
In [66]: arr[idx].std(axis=0)
Out[66]: 
array([22.67653383, 10.3940773 , 14.60076482, 13.82801944, 13.68038469,
       12.54834004, 13.13574418, 15.24698722, 14.65383773, 11.62092989,
        8.57331689,  4.76392583,  9.49404494, 21.20874383, 24.91417226,
       20.84991841, 13.22152789, 10.83343482, 16.01294245, 13.80007894,
       10.51866421,  8.29287433, 11.24933733, 15.43661128, 13.65945978])

使用as_strided 的滚动窗口可能会更快,但可能更难理解。

In [67]: timeit std= np.array([arr[i:i+number].std() for i in range(0, len(arr)-
    ...: number)])
1.05 ms ± 7.01 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [68]: timeit np.array([arr[i:i+number] for i in range(0, len(arr)-number)]).s
    ...: td(axis=1)
74.7 µs ± 108 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [69]: %%timeit
    ...: idx = np.arange(0,len(arr)-number)
    ...: idx = np.linspace(idx,idx+number,number, endpoint=False,dtype=int)
    ...: arr[idx].std(axis=0)
117 µs ± 240 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [73]: timeit np.std(rolling_window(arr, 5), 1)
74.5 µs ± 625 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

使用更直接的方式生成滚动索引:

In [81]: %%timeit
    ...: idx = np.arange(len(arr)-number)[:,None]+np.arange(number)
    ...: arr[idx].std(axis=1)
57.9 µs ± 87.5 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

你的错误

In [82]: arr[np.array([1,2,3]):np.array([4,5,6])]
Traceback (most recent call last):
  File "<ipython-input-82-3358e59f8fb5>", line 1, in <module>
    arr[np.array([1,2,3]):np.array([4,5,6])]
TypeError: only integer scalar arrays can be converted to a scalar index

【讨论】:

  • 感谢您的详细解释,难道没有我可以避免 for 循环的地方吗?我试图让我的代码运行得更快。
  • 我的错,我不是故意以不尊重的方式离开。我只是不太了解asstrided 部分
  • 只需将std 移出循环即可获得超过 10 倍的改进。 as_strided 版本不是最快的,所以如果您不理解它,请不要担心。如何取多个切片的问题经常出现。一个简单的切片很快(一个视图),但多个切片需要某种形式的复制 - 高级索引或连接。
  • 是的,我想我可以实现最后一个需要57.9 µs 来完成的程序,该程序使用了一个长度超过 200 万的非常长的列表,并且它因错误消息 @987654337 而崩溃@。但无论如何,谢谢。
  • 是的,对于较大的数组,可能需要像您最初所做的那样进行迭代。即使您没有内存错误,内存管理和迭代之间也存在时间权衡。您也可以考虑使用numba 来编译任务。
【解决方案2】:

取自Rolling window for 1D arrays in Numpy?

def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

np.std(rolling_window(list_, 5), 1)

顺便说一句,您的原版 python 代码是错误的。应该是:

std= np.array([list_[i:i+number].std() for i in range(0, len(list_)-number+1)])

【讨论】:

  • 我正在尝试更快地运行我的代码,有没有一种方法可以在没有 for 循环的情况下创建函数。
  • 使用我在第一个框中编写的代码。它应该在没有 for 循环的情况下给出你需要的结果。
猜你喜欢
  • 1970-01-01
  • 2011-07-27
  • 2018-01-22
  • 2023-03-30
  • 2011-10-23
  • 2018-10-25
  • 2019-12-23
  • 1970-01-01
  • 2017-06-24
相关资源
最近更新 更多