web-dev-qa-db-ja.com

Pandas DataFrame検索は線形時間ですか、それとも一定時間ですか?

次のような15000行を超えるデータフレームオブジェクトdfがあります。

anime_id          name              genre    rating
1234      Kimi no nawa    Romance, Comedy     9.31
5678       Stiens;Gate             Sci-fi     8.92

そして、私は特定のanime_idの行を見つけようとしています。

a_id = "5678"
temp = (df.query("anime_id == "+a_id).genre)

この検索が一定時間(辞書のように)で行われたのか、線形時間(リストのように)で行われたのかを知りたかっただけです。

13
Sayan Sil

これは非常に興味深い質問です!

私はそれが次の側面に依存すると思います:

インデックスによる単一行へのアクセス(インデックスはソートされて一意)にはランタイムO(m)が必要です。ここで_m << n_rows_

インデックスによる単一行へのアクセス(インデックスは一意ではなく、ソートされていません)にはランタイムが必要ですO(n_rows)

インデックスによる単一行へのアクセス(インデックスは一意ではなく、並べ替えられます)にはランタイムO(m)が必要です。ここで `m <n_rows)

ブールインデックス作成による(インデックスとは独立した)行へのアクセスshoudlにはランタイムO(n_rows)があります。


デモ:

インデックスはソートされて一意です:

_In [49]: df = pd.DataFrame(np.random.Rand(10**5,6), columns=list('abcdef'))

In [50]: %timeit df.loc[random.randint(0, 10**4)]
The slowest run took 27.65 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 331 µs per loop

In [51]: %timeit df.iloc[random.randint(0, 10**4)]
1000 loops, best of 3: 275 µs per loop

In [52]: %timeit df.query("a > 0.9")
100 loops, best of 3: 7.84 ms per loop

In [53]: %timeit df.loc[df.a > 0.9]
100 loops, best of 3: 2.96 ms per loop
_

インデックスはソートされておらず、一意ではありません:

_In [54]: df = pd.DataFrame(np.random.Rand(10**5,6), columns=list('abcdef'), index=np.random.randint(0, 10000, 10**5))

In [55]: %timeit df.loc[random.randint(0, 10**4)]
100 loops, best of 3: 12.3 ms per loop

In [56]: %timeit df.iloc[random.randint(0, 10**4)]
1000 loops, best of 3: 262 µs per loop

In [57]: %timeit df.query("a > 0.9")
100 loops, best of 3: 7.78 ms per loop

In [58]: %timeit df.loc[df.a > 0.9]
100 loops, best of 3: 2.93 ms per loop
_

インデックスは一意ではなく、並べ替えられます:

_In [64]: df = pd.DataFrame(np.random.Rand(10**5,6), columns=list('abcdef'), index=np.random.randint(0, 10000, 10**5)).sort_index()

In [65]: df.index.is_monotonic_increasing
Out[65]: True

In [66]: %timeit df.loc[random.randint(0, 10**4)]
The slowest run took 9.70 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 478 µs per loop

In [67]: %timeit df.iloc[random.randint(0, 10**4)]
1000 loops, best of 3: 262 µs per loop

In [68]: %timeit df.query("a > 0.9")
100 loops, best of 3: 7.81 ms per loop

In [69]: %timeit df.loc[df.a > 0.9]
100 loops, best of 3: 2.95 ms per loop
_
4
MaxU

それがどのように実装されたかはわかりませんが、少しテストを実行した後です。データフレームのブールマスクは線形に似ているようです。

>>> timeit.timeit('dict_data[key]',setup=setup,number = 10000)
0.0005770014540757984
>>> timeit.timeit('df[df.val==key]',setup=setup,number = 10000)
17.583375428628642
>>> timeit.timeit('[i == key for i in dict_data ]',setup=setup,number = 10000)
16.613936403242406
4
galaxyan

インデックスが一意の場合、ilocでさえハッシュマップよりも約2桁遅いことに注意してください。

df = pd.DataFrame(np.random.randint(0, 10**7, 10**5), columns=['a'])
%timeit df.iloc[random.randint(0,10**5)]
10000 loops, best of 3: 51.5 µs per loop

s = set(np.random.randint(0, 10**7, 10**5))
%timeit random.randint(0,10**7) in s
The slowest run took 9.70 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 615 ns per loop
1
blacknight12321