簡體   English   中英

沿numpy數組中的范圍應用函數

[英]Apply function along ranges in numpy array

說我有以下numpy數組:

a = np.arange(20)

還有一個包含索引的數組,如下所示:

ix = np.array([4,10,15])

我一直在試圖想出一個量化的解決了以下問題:我如何才能沿着應用功能, a使用的索引被分裂ix

所以說,我哪里拆分anp.split (我只使用np.split這里說明組,我想在這里應用功能):

np.split(a,ix)

[array([0, 1, 2, 3]),
 array([4, 5, 6, 7, 8, 9]),
 array([10, 11, 12, 13, 14]),
 array([15, 16, 17, 18, 19])]

並舉例說,我想取每個塊的總和,因此給出:

[6, 39, 60, 85]

我如何使用numpy將其向量化?

我不知道這是否是最好的解決方案,但是您可以通過添加零將具有不同大小的數組列表轉換為固定大小的數組列表。 然后實現諸如sum之類的不受零影響的函數。

請參閱下面的示例。

a = np.arange(20)
ix = np.array([4,10,15])
b = np.split(a,ix)
print(b)

結果是

[array([0, 1, 2, 3]),
 array([4, 5, 6, 7, 8, 9]),
 array([10, 11, 12, 13, 14]),
 array([15, 16, 17, 18, 19])]

然后使用itertools 從此處將列表轉換為數組

import itertools
c = np.array(list(itertools.zip_longest(*b, fillvalue=0))).T
print(c)

導致

[[ 0  1  2  3  0  0]
 [ 4  5  6  7  8  9]
 [10 11 12 13 14  0]
 [15 16 17 18 19  0]]

然后使用

np.sum(c, axis = 1)

結果是

array([ 6, 39, 60, 85])

split生成數組列表,其長度可能不同。 它實際上是反復進行的

In [12]: alist = []
In [13]: alist.append(a[0:idx[0]])
In [14]: alist.append(a[idx[0]:idx[1]])
In [15]: alist.append(a[idx[1]:idx[2]])
....

sum分別應用於列表的每個元素是有意義的:

In [11]: [np.sum(row) for row in alist]
Out[11]: [6, 39, 60, 85]

當您擁有形狀各異的數組列表時,可以肯定的是,您將必須對其進行Python級迭代。

快速的“向量化”意味着以編譯后的代碼執行計算。 大多數是圍繞多維數組構建的,例如二維數組。 如果split產生的數組大小相等,則可以將np.sum與相應的axis參數一起使用。

In [23]: a1 = a.reshape(4,5)
In [24]: a1
Out[24]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])
In [25]: np.sum(a1, axis=1)
Out[25]: array([10, 35, 60, 85])

有時我們可以玩弄技巧,將問題轉化為第一個問題,例如,如果拆分的第一個數組用0填充。但是該轉化本身可能需要迭代。

如此處(及其鏈接)所述,AttributeError的起源:對象沒有將屬性' ufuncufunc )函數應用於對象dtype數組,最終將操作委派給了對象的相應方法。 但這仍然涉及對象的(近)Python級迭代。


一些時間:

In [57]: timeit [np.sum(row) for row in alist]
31.7 µs ± 1.21 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [58]: timeit np.sum(list(itertools.zip_longest(*alist, fillvalue=0)),axis=0)
25.2 µs ± 82 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [59]: timeit np.nansum(pd.DataFrame(alist), axis=1)
908 µs ± 28.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [61]: timeit np.frompyfunc(sum,1,1)(alist)
12.9 µs ± 21.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

在這最后一種情況下,Python的sumnp.sum快。 但是列表理解也是這樣:

In [63]: timeit [sum(row) for row in alist]
6.86 µs ± 13.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

使用Divakar的wiz-bang fillnaNumpy:通過用零填充空元素來修復具有不同長度的行的數組

In [70]: timeit numpy_fillna(np.array(alist)).sum(axis=1)
44.2 µs ± 208 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

一旦有了多維數組,numpy代碼就會很快。 但是,如果從列表開始,甚至從數組列表開始,Python列表方法通常會更快。 構造數組(或數據框)所花費的時間從來都不短。

大熊貓解決方案將是:

import numpy as np
import pandas as pd

a = np.arange(20)

ix = np.array([4, 10, 15])

data = pd.DataFrame(np.split(a, ix))

print(np.nansum(data, axis=1))

產量

[ 6. 39. 60. 85.]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM