近期並無什麼系統性的學習感悟,反而是在項目過程當中練就了一些奇技淫巧。最近作的工做大部分都跟優化執行效率有關,把原來要泡茶等的代碼優化到快如閃電,有時候仍是很是有意思的,順便跟大神們聊天也受益良多,記錄一下最近用到的一些之後可能還會反覆用的技巧吧:python
一、在array中儲存tupleapp
你試過在array中儲存tuple嗎?這個問題有些蛋疼,但特殊需求沒辦法。我一開始覺得這個問題很簡單,但沒想到tuple進去全變list了……致使我後來找某個特定的tuple時提示找不到。有人可能會說list和tuple差很少啊,但tuple是hashable的,這也是咱們堅持要tuple的緣由。dom
idx = [("a", 1), ("a", 2), ("b", 5)] np.array(idx)
你獲得的結果會是:函數
array([['a', '1'], ['a', '2'], ['b', '5']], dtype='<U1')
驚不驚喜?意不意外?後來總算找到了一種方法,必須先新建一個空的array,並制定dtype,以後再賦值:oop
arr = np.empty((len(idx)), dtype="object") arr[:] = idx arr
如今你獲得的結果是:學習
array([('a', 1), ('a', 2), ('b', 5)], dtype=object)
二、數值最大(或最小)的前n項所對應的對象優化
有點繞口,舉個例子說,我有學生ABCDE,我還有一次考試的成績,我想知道班級前三是誰。我原來想的是用OrderedDict,後來大神教了我正宗numpy方法,速度固然沒的說:spa
# 最小前3項(帶排序) student = np.array(["A", "B", "C", "D", "E", "F", "G"]) score = np.array([92, 84, 93, 85, 83, 88, 91]) nth = 3 student[np.argpartition(score, nth-1)[:nth]]
結果:code
array(['E', 'B', 'D'], dtype='<U1')
若是要最大,加個負號就好了:對象
# 最大前4項(帶排序) student = np.array(["A", "B", "C", "D", "E", "F", "G"]) score = np.array([92, 84, 93, 85, 83, 88, 91]) nth = 4 student[np.argpartition(-score, nth-1)[:nth]]
結果:
array(['C', 'A', 'G', 'F'], dtype='<U1')
三、函數矢量化(向量化)
你有沒有過apply的痛苦經驗?當數據量不斷增大以後,你會發現稍微複雜的一個apply會變得很是慢,尤爲是涉及多列的apply。這時候要如何才能擺脫龜速呢?我當時第一想法是numba?然而numba不用@njit至關於白用,但@njit不支持不少python原生的類型(好比dict),更別談支持DataFrame了。這時候你須要的是np.vectorize:
首先咱們隨便弄一些數據,先來個5W行吧
df = pd.DataFrame({"a":np.random.random(50000), "b":np.random.random(50000)})
而後咱們的函數是個基於a、b兩列的條件判斷:
def func(a, b): if (a < 0.5) & (b < 0.5): return 1 elif (a >=0.5) & (b < 0.5): return 2 else: return 3
按照傳統的apply方法咱們運行一下:
%%timeit df["c"] = df.apply(lambda row: func(row["a"], row["b"]), axis=1)
結果:
1.11 s ± 32.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
好了,如今上魔法,只需短短一行:
v_func = np.vectorize(func)
再來計時一下看看:
%%timeit df["c"] = v_func(df["a"], df["b"])
結果:
13.4 ms ± 294 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
快如閃電!現已加入特徵工程套餐。