2017-03-25 9 views
8

さまざまなサイズの分布から無作為にサンプリングすると、実行時間は、サンプリングされるデータセットのサイズではなく、サンプリングされるデータセットのサイズにほぼ比例しているようです。例:データセットのランダムサンプリングのスケールがサンプルサイズでないのはなぜですか? (パンダサンプル()の例)

import pandas as pd 
import numpy as np 
import time as tm 

#generate a small and a large dataset 
testSeriesSmall = pd.Series(np.random.randn(10000)) 
testSeriesLarge = pd.Series(np.random.randn(10000000)) 

sampleSize = 10 
tStart = tm.time() 
currSample = testSeriesLarge.sample(n=sampleSize).values 
print('sample %d from %d values: %.5f s' % (sampleSize, len(testSeriesLarge), (tm.time() - tStart))) 

tStart = tm.time() 
currSample = testSeriesSmall.sample(n=sampleSize).values 
print('sample %d from %d values: %.5f s' % (sampleSize, len(testSeriesSmall), (tm.time() - tStart))) 

sampleSize = 1000 
tStart = tm.time() 
currSample = testSeriesLarge.sample(n=sampleSize).values 
print('sample %d from %d values: %.5f s' % (sampleSize, len(testSeriesLarge), (tm.time() - tStart))) 

tStart = tm.time() 
currSample = testSeriesSmall.sample(n=sampleSize).values 
print('sample %d from %d values: %.5f s' % (sampleSize, len(testSeriesSmall), (tm.time() - tStart))) 

出力は次のようになります。

sample 10 from 10000 values: 0.00126 s 
sample 10 from 10000000 values: 1.10504 s 
sample 1000 from 10000 values: 0.00122 s 
sample 1000 from 10000000 values: 1.15000 s 

これは直感に反するようです。たぶん私は密集していますが、問題はランダムなインデックスのリストを生成するのと同じように思えますし、問題のサンプリングされた値の数とデータセットのサイズがそれほど重要ではないことが予想されます。私は別の実装を試してみましたが、2つの同様の結果がありましたが、根本的な問題がなくなっているように感じ始めています。

私の質問は2つあります:(1)これはファンダの基本的な問題か実施の奇跡ですか? (2)このように大規模なデータセットから無作為にサンプルを採取することができるかなり高速なアプローチがありますか?あなたのケースで

答えて

7

pandas.Series.sample()はこれに沸く:

rs = np.random.RandomState() 
locs = rs.choice(axis_length, size=n, replace=False) 
return self.take(locs) 

遅い部分がrs.choice()です:

%timeit rs.choice(100000000, size=1, replace=False) 
1 loop, best of 3: 9.43 s per loop 

それは、単一の乱数を生成するのに約10秒かかります!最初の引数を10で割った場合、約1秒かかります。それは遅いです!

replace=Trueを使用すると、超高速です。あなたの結果に重複したエントリーがあってもかまいません。

choice(replace=False)ためのnumpyのドキュメントは言う:

これはnp.random.permutation(np.arange(5))と等価です[:3]かなりの問題を説明し

- 可能な値の膨大な配列を生成し、それらをシャッフルしてから最初のNを取ります。これはパフォーマンス上の問題の根本的な原因であり、ここNumPyの問題として既に報告されています:同じランダムシード値を使用する場合、choice()の結果に(NumPyのバージョン間で)変化しないことに依存しているため、NumPyで修正することは明らかに困難です。

def sample(series, n): 
    locs = np.random.randint(0, len(series), n*2) 
    locs = np.unique(locs)[:n] 
    assert len(locs) == n, "sample() assumes n << len(series)" 
    return series.take(locs) 

はるかに高速回を与える:

sample 10 from 10000 values: 0.00735 s 
sample 10 from 1000000 values: 0.00944 s 
sample 10 from 100000000 values: 1.44148 s 
sample 1000 from 10000 values: 0.00319 s 
sample 1000 from 1000000 values: 0.00802 s 
sample 1000 from 100000000 values: 0.01989 s 
sample 100000 from 1000000 values: 0.05178 s 
sample 100000 from 100000000 values: 0.93336 s 
+1

ああ、そうです。私は、 "同等"がセマンティクスを説明するだけであると思っていましたが、明らかに実際にはそのように実装されています(https://github.com/numpy/numpy/blob/3e297ba7e47c949469744ac67cf296b4315ceea9/numpy/random/mtrand/mtrand.pyx #L1174)。それは地獄のように遅いです。 – user2357112

4

これは内部numpyの問題になりそうだ、あなたのユースケースが非常に狭いので

は、あなたがこのような何かを行うことができます。私はパンダsampleメソッドnumpy.random.choiceを呼び出すと思います。 numpyがさまざまな配列サイズとサンプルサイズでどのように機能するかを見てみましょう。

配列

large = np.arange(1000000) 
small = np.arange(1000) 

時間交換せずにサンプル

%timeit np.random.choice(large, 10, replace=False) 
10 loops, best of 3: 27.4 ms per loop 

%timeit np.random.choice(small, 10, replace=False) 
10000 loops, best of 3: 41.4 µs per loop 

時間、交換せずに大きな配列をサンプルをやって非常に興味深いことに、交換

%timeit np.random.choice(large, 10, replace=True) 
100000 loops, best of 3: 11.7 µs per loop 

%timeit np.random.choice(small, 10, replace=True) 
100000 loops, best of 3: 12.2 µs per loop 

、とのサンプルを作成します。 3桁近い長さを取っており、それはちょうど3桁のマグニチュードは大きい。これは、numpyが配列をランダムにソートしてから最初の10個の項目を取っていることを示唆しています。

置換でサンプリングする場合、各値はタイミングが同一になるように独立して選択されます。

関連する問題