2016-08-18 3 views
1

を列挙することなく、numpyの配列を作成します(お知らせ、最初の項目の繰り返しを)しかし、私は最初の項目は繰り返すことなく、このより速く得ることができる場合、私が最初にnp.hstackをすることができます項目。この以降では、配列

[[58 58 56 54 52] 
[56 56 54 52 50] 
[54 54 52 50 48] 
[52 52 50 48 46] 
[50 50 48 46 44] 
[48 48 46 44 42] 
[46 46 44 42 40] 
[44 44 42 40 38] 
[42 42 40 38 36] 
[40 40 38 36 34] 
[38 38 36 34 32] 
[36 36 34 32 30] 
[34 34 32 30 None] 
[32 32 30 None None] 
[30 30 None None None]] 

以下のコードは、 'for'ループと列挙なしでより速く動作します。

arr = np.empty((0,5), int) 

for i,e in enumerate(x): 
    arr2 = np.hstack((x[i], x[i:i+4], np.asarray([None]*5)))[:5] 
    arr = np.vstack((arr,arr2)) 
+0

私は毎回まったく新しいオブジェクトを作成する必要があるので、 'np._stack()'を取り除きます。また、 'None'を数値型で表すことができる場合は:inf maybe ..' dtype = object'の速度低下を避けることができます – Aaron

+1

浮動小数点数で暮らすことができれば、NaNを使うことができるからです。 –

+0

「なし」はデータベースの問題です。 – Merlin

答えて

5

アプローチ#1

ここで用いたベクトル化手法だNumPy broadcasting -

N = 4 # width factor 
x_ext = np.concatenate((x,[None]*(N-1))) 
arr2D = x_ext[np.arange(N) + np.arange(x_ext.size-N+1)[:,None]] 
out = np.column_stack((x,arr2D)) 

アプローチ#2

ここで使用して別のだhankel -

from scipy.linalg import hankel 

N = 4 # width factor 
x_ext = np.concatenate((x,[None]*(N-1))) 
out = np.column_stack((x,hankel(x_ext[:4], x_ext[3:]).T)) 

ランタイムテスト

ここで公正なベンチマークのために、そのスクリプトに彼のポストのために使用されるものと同じで、このポストのための入力フォーマットを使用して、これら2にだけ焦点を当て@Aaron's benchmarking scriptの修正版ですアプローチ -

upper_limit = 58 # We will edit this to vary the dataset sizes 

print "Timings are : " 
t = time() 
for _ in range(1000): #1000 iterations of @Aaron's soln. 
    width = 3 
    x = np.array(range(upper_limit,28,-2) + [float('nan')]*width) 
    arr = np.empty([len(x)-width, width+2]) 
    arr[:,0] = x[:len(x)-width] 
    for i in xrange(len(x)-width): 
     arr[i,1:] = x[i:i+width+1] 
print(time()-t) 

t = time() 
for _ in range(1000): 
    N = 4 # width factor 
    x_ext = np.array(range(upper_limit,28,-2) + [float('nan')]*(N-1)) 
    arr2D = x_ext[np.arange(N) + np.arange(x_ext.size-N+1)[:,None]] 
    out = np.column_stack((x_ext[:len(x_ext)-N+1],arr2D)) 
print(time()-t) 

ケース#1(upper_limit = 58):

Timings are : 
0.0316879749298 
0.0322730541229 

ケース#2(upper_limit = 1058):

Timings are : 
0.680443048477 
0.124517917633 

ケース#3(upper_limit = 5058):

我々以来Divakerのパッド入り x

N = 4 # width factor 
x_ext = np.concatenate((x,[None]*(N-1))) 

を皮切り

Timings are : 
3.28129291534 
0.47504901886 
+1

そんなに馬鹿馬鹿しいPythonのforループをスクロールして4行の答えを見てみましょう。まあ、あなたは一番下にいません... –

+0

@MadPhysicist私はスピードxPに夢中になりましたが、実際には私の元のポストはわずか6行でした。 – Aaron

+2

少しストライドトリッキーで書くことができます: 'arr2D = np。 lib.stride_tricks.as_strided(x_ext、shape =(15,4)、strides =(4,4)) ' – hpaulj

3

私は速く_stack()を回避し、唯一の山車を使用して約一桁だ...

編集:タイムトライアルにDivakarのポスト@追加...うち

import numpy as np 
from time import time 

t = time() 
for _ in range(1000): #1000 iterations of my soln. 
    width = 3 
    x = np.array(range(58,28,-2) + [float('nan')]*width) 
    arr = np.empty([len(x)-width, width+2]) 
    arr[:,0] = x[:len(x)-width] 
    for i in xrange(len(x)-width): 
     arr[i,1:] = x[i:i+width+1] 
print(time()-t) 

t = time() 
for _ in range(1000): #1000 iterations of OP code 
    x = range(30,60,2)[::-1]; 
    x = np.asarray(x) 
    arr = np.empty((0,5), int) 
    for i,e in enumerate(x): 
     arr2 = np.hstack((x[i], x[i:i+4], np.asarray([None]*5)))[:5] 
     arr = np.vstack((arr,arr2)) 
print(time()-t) 

t = time() 
for _ in range(1000): 
    x = np.array(range(58,28,-2)) 
    N = 4 # width factor 
    x_ext = np.hstack((x,[None]*(N-1))) 
    arr2D = x_ext[np.arange(N) + np.arange(x_ext.size-N+1)[:,None]] 
    out = np.column_stack((x,arr2D)) 
print(time()-t) 

プリント:

>>> runfile('...temp.py', wdir='...') 
0.0160000324249 
0.374000072479 
0.0319998264313 
>>> 
2

同じ列の初期行列を作成し、0を使用することをお勧めしますは、それらを回転させる:

import numpy as np 
import timeit as ti 
import numpy.matlib 

x = range(30,60,2)[::-1]; 
x = np.asarray(x); 

def sol1(): 
    # Your solution, for comparison 
    arr = np.empty((0,5), int) 

    for i,e in enumerate(x): 
     arr2 = np.hstack((x[i], x[i:i+4], np.asarray([None]*5)))[:5] 
     arr = np.vstack((arr,arr2)) 
    return arr 

def sol2(): 
    # My proposal 
    x2 = np.hstack((x, [None]*3)) 
    mat = np.matlib.repmat(x2, 5, 1) 
    for i in range(3): 
     mat[i+2, :] = np.roll(mat[i+2, :], -(i+1)) 
    return mat[:,:-3].T 


print(ti.timeit(sol1, number=100)) 
print(ti.timeit(sol2, number=100)) 

guivesた:

0.026760146000015084 
0.0038611710006080102 

それは、forループを使用しますが、それだけ反復する短軸の上に。また、ハードコードされた番号を使用する代わりに、このコードを他の構成に適用するのは難しいことではありません。

+1

timeitの出力を投稿できますか? –

+0

あります。/ – josoler

+0

それは実際に@Divakarよりも2倍以上遅く応答します – josoler

3

(オブジェクト配列を作る)Noneか、またはnp.nan(これはflオートムギ)は大きな違いはありません。

列スタックインデクシングにほとんど変化して排除することができる:

idx = np.r_[0,np.arange(N)] + np.arange(x_ext.size-N+1)[:,None] 

これは

array([[ 0, 0, 1, 2, 3], 
     [ 1, 1, 2, 3, 4], 
     [ 2, 2, 3, 4, 5], 
     [ 3, 3, 4, 5, 6], 
     [ 4, 4, 5, 6, 7], 
     ... 

を生成するので、完全な結果が

x_ext[idx] 

ある==== ============

異なるアプローチは、ストライドを使用して一種のローリングウィンドウを作成することです。

as_strided = np.lib.stride_tricks.as_strided 
arr2D = as_strided(x_ext, shape=(15,4), str‌​ides=(4,4)) 

これはas_stridedのより簡単なアプリケーションの1つです。 shapeはまっすぐです - 希望の結果の形状(繰り返し列なし)(x.shape[0],N)

In [177]: x_ext.strides 
Out[177]: (4,) 

このタイプの1d配列の場合、次の項目へのステップは4バイトです。配列を3列の2dに変更すると、次の行のストライドは12 - 3 * 4(3オフセット)になります。

In [181]: x_ext.reshape(6,3).strides 
Out[181]: (12, 4) 

strides=(4,4)使用は、次の行へステップはちょうど4バイト、元の内の1つの要素であることを意味します。

as_strided(x_ext,shape=(8,4),strides=(8,4)) 

2アイテム重複

array([[58, 56, 54, 52], 
     [54, 52, 50, 48], 
     [50, 48, 46, 44], 
     [46, 44, 42, 40], 
     .... 

を生成as_stridedの潜在的に危険な部分は、元のデータバッファの外側アレイをサンプリング・メモリを作成することが可能であるということです。通常、この例ではNoneと表示されている大きな乱数として表示されます。これは、あなたが配列ポインタとインデックスを使用することに不注意だった場合、Cコードで遭遇するのと同じ種類のエラーです。

as_stridedアレイはビューです(繰り返し値はコピーされません)。その配列への書き込みは危険です。 とxはコピーを作成し、必要に応じて繰り返し値を複製します。