有關爲什麼Python中的某些操作方式「應該」更快的說法不能過於嚴肅,因爲您經常測量在某些情況下可能表現不同的實現細節。因此,當人們猜測應該更快時,他們經常(通常?)錯誤。例如,我發現map
實際上可能會變慢。使用此設置代碼:
import numpy as np, pandas as pd
import random, string
def make_test(num, width):
s = [''.join(random.sample(string.ascii_lowercase, width)) for i in range(num)]
df = pd.DataFrame({"a": s})
return df
讓我們比較一下,他們才能使索引對象的時間 - 無論是Series
或list
- 它需要使用該對象索引到DataFrame
產生的時間。例如,可以將列表製作得很快,但在將其用作索引之前,需要將其內部轉換爲Series
或ndarray
或其他東西,因此在那裏添加了額外的時間。
首先,對於一個小幀:
>>> df = make_test(10, 10)
>>> %timeit df['a'].map(lambda x: x.startswith('t'))
10000 loops, best of 3: 85.8 µs per loop
>>> %timeit [x.startswith('t') for x in df['a']]
100000 loops, best of 3: 15.6 µs per loop
>>> %timeit df['a'].str.startswith("t")
10000 loops, best of 3: 118 µs per loop
>>> %timeit df[df['a'].map(lambda x: x.startswith('t'))]
1000 loops, best of 3: 304 µs per loop
>>> %timeit df[[x.startswith('t') for x in df['a']]]
10000 loops, best of 3: 194 µs per loop
>>> %timeit df[df['a'].str.startswith("t")]
1000 loops, best of 3: 348 µs per loop
並且在這種情況下,listcomp是最快的。這實際上並沒有讓我感到吃驚,說實話,因爲通過lambda
可能會比直接使用str.startswith
慢,但它很難猜測。 10足夠小,我們可能仍在測量像Series
的設置成本;在更大的框架中會發生什麼?
>>> df = make_test(10**5, 10)
>>> %timeit df['a'].map(lambda x: x.startswith('t'))
10 loops, best of 3: 46.6 ms per loop
>>> %timeit [x.startswith('t') for x in df['a']]
10 loops, best of 3: 27.8 ms per loop
>>> %timeit df['a'].str.startswith("t")
10 loops, best of 3: 48.5 ms per loop
>>> %timeit df[df['a'].map(lambda x: x.startswith('t'))]
10 loops, best of 3: 47.1 ms per loop
>>> %timeit df[[x.startswith('t') for x in df['a']]]
10 loops, best of 3: 52.8 ms per loop
>>> %timeit df[df['a'].str.startswith("t")]
10 loops, best of 3: 49.6 ms per loop
現在好像作爲索引使用時map
是贏,但差異是微不足道的。但速度並不快:如果我們手動將listcomp變成array
或Series
,該怎麼辦?
>>> %timeit df[np.array([x.startswith('t') for x in df['a']])]
10 loops, best of 3: 40.7 ms per loop
>>> %timeit df[pd.Series([x.startswith('t') for x in df['a']])]
10 loops, best of 3: 37.5 ms per loop
現在listcomp再次獲勝!
結論:誰知道?但是,如果沒有timeit
的結果,就不要相信任何事情,即使如此,你也必須問你是否在測試你的想法。
我敢打賭,你從操作員導入methodcaller \\ df2 ['a']。map(methodcaller(「startswith」,「t」))'會明顯更快。 – Veedrac
@TimPietzcker;它不使用內置的map(在這種情況下會更慢)。 – Veedrac
@Veedrac:我明白了;我只是想知道'map'的第二個參數是在哪裏: –