陷阱一:數(shù)據(jù)結(jié)構(gòu)混亂
array 和 matrix 都可以用來表示多維矩陣:
看起來效果不錯(cuò)。假設(shè)我們要對數(shù)據(jù)進(jìn)行篩選,取第 1 列的第 1 行和第 3 行數(shù)據(jù)構(gòu)成一個(gè) 2 x 1 的列向量。先看對 array 的做法:
從 Out[101] 可以看到一個(gè)陷阱,a[:, 0] 過濾完應(yīng)該是一個(gè) 3 x 1 的列向量,可是它變成了行向量。其實(shí)也不是真正意義上的行向量,因?yàn)樾邢蛄?shape 應(yīng)該是 3 x 1,可是他的 shape 是 (3,) ,這其實(shí)已經(jīng)退化為一個(gè)數(shù)組了。所以,導(dǎo)致最后 In [110] 出錯(cuò)。只有像 In [111] 那樣 reshape 一下才可以。我不知道大家暈了沒有,我是已經(jīng)快暈了。
相比之下,matrix 可以確保運(yùn)算結(jié)果全部是二維的,結(jié)果相對好一點(diǎn)。為什么只是相對好一點(diǎn)呢?呆會兒我們再來吐吐 matrix 的槽點(diǎn)。
看起來還不錯(cuò)。不過槽點(diǎn)就來了。Out [114] 我們預(yù)期的輸入結(jié)果應(yīng)該是一個(gè) 2 x 1 的列向量,可是這里變成了 1 x 2 的行向量!
為什么我會在意行向量和列向量?在矩陣運(yùn)算里,行向量和列向量是不同的。比如一個(gè) m x 3 的矩陣可以和 3 x 1 的列向量叉乘,結(jié)果是 m x 1 的列向量。而如果一個(gè) m x 3 的矩陣和 1 x 3 的行向量叉乘是會報(bào)錯(cuò)的。
陷阱二:數(shù)據(jù)處理能力不足,語言效率低
我們再看個(gè)例子。假設(shè) X 是 5 x 2 的矩陣,Y 是 5 X 1 的 bool 矩陣,我們想用 Y 來過濾 X ,即取出 Y 值為 True 的項(xiàng)的索引,拿這些索引去 X 里找出對應(yīng)的行,再組合成一個(gè)新矩陣。
我們預(yù)期 X 過濾完是 3 x 2 列的矩陣,但不幸的是從 Out[81] 來看 numpy 這樣過濾完只會保留第一列的數(shù)據(jù),且把它轉(zhuǎn)化成了行向量,即變成了 1 x 3 的行向量。不知道你有沒有抓狂的感覺。如果按照 In [85] 的寫法,還會報(bào)錯(cuò)。如果要正確地過濾不同的列,需要寫成 In [86] 和 In [87] 的形式。但是即使寫成 In [86] 和 In [87] 的樣式,還是一樣把列向量轉(zhuǎn)化成了行向量。所以,要實(shí)現(xiàn)這個(gè)目的,得復(fù)雜到按照 In [88] 那樣才能達(dá)到目的。實(shí)際上,這個(gè)還達(dá)不到目的,因?yàn)槟抢锩鎸懥撕枚嘤簿幋a的數(shù)字,要處理通用的過濾情況,還需要寫個(gè)函數(shù)來實(shí)現(xiàn)。而這個(gè)任務(wù)在 matlab/octave 里只需要寫成 X(Y==1, :) 即可完美達(dá)成目的。
陷阱三:數(shù)值運(yùn)算句法混亂
在機(jī)器學(xué)習(xí)算法里,經(jīng)常要做一些矩陣運(yùn)算。有時(shí)候要做叉乘,有時(shí)候要做點(diǎn)乘。我們看一下 numpy 是如何滿足這個(gè)需求的。
假設(shè) x, y, theta 的值如下,我們要先讓 x 和 y 點(diǎn)乘,再讓結(jié)果與 theta 叉乘,最后的結(jié)果我們期望的是一個(gè) 5 x 1 的列向量。
直觀地講,我們應(yīng)該會想這樣做:(x 點(diǎn)乘 y) 叉乘 theta。但很不幸,當(dāng)你輸入 x * y 時(shí)妥妥地報(bào)錯(cuò)。那好吧,我們這樣做總行了吧,x[:, 0] * y 這樣兩個(gè)列向量就可以點(diǎn)乘了吧,不幸的還是不行,因?yàn)?numpy 認(rèn)為這是 matrix,所以執(zhí)行的是矩陣相乘(叉乘),要做點(diǎn)乘,必須轉(zhuǎn)為 array 。
所以,我們需要象 In [39] 那樣一列列轉(zhuǎn)為 array 和 y 執(zhí)行點(diǎn)乘,然后再組合回 5 x 3 的矩陣。好不容易算出了 x 和 y 的點(diǎn)乘了,終于可以和 theta 叉乘了。
看起來結(jié)果還不錯(cuò),但實(shí)際上這里面也是陷阱重重。
In [45] 會報(bào)錯(cuò),因?yàn)樵?array 里 * 運(yùn)算符是點(diǎn)乘,而在 matrix 里 * 運(yùn)算符是叉乘。如果要在 array 里算叉乘,需要用 dot 方法??雌饋硖峁┝遂`活性,實(shí)際上增加了使用者的大腦負(fù)擔(dān)。而我們的需求在 matlab/octave 里只需要寫成 x .* y * theta ,直觀優(yōu)雅。
陷阱四:語法復(fù)雜,不自然
比如,我們要在一個(gè) 5 x 2 的矩陣的前面加一列全部是 1 的數(shù)據(jù),變成一個(gè) 5 x 3 的矩陣,我們必須這樣寫:
有興趣的人可以數(shù)數(shù) In [18] 里有多少個(gè)括號,還別不服,括號寫少了妥妥地報(bào)錯(cuò)。而這個(gè)需求在 matlab/octave 里面只需要寫成[ones(5,1) x],瞬間腦袋不短路了,直觀優(yōu)雅又回來了。
結(jié)論
有人說 python 是機(jī)器學(xué)習(xí)和數(shù)據(jù)分析的新貴,但和專門的領(lǐng)域語言 matlab/octave 相比,用起來確實(shí)還是比較別扭的。當(dāng)然有些槽點(diǎn)是因?yàn)檎Z言本身的限制,比如 python 不支持自定義操作符,導(dǎo)致 numpy 的一些設(shè)計(jì)不夠優(yōu)雅和直觀,但默認(rèn)把列向量轉(zhuǎn)化為行向量的做法只能說是 numpy 本身的設(shè)計(jì)問題了。這或許就是 Andrew Ng 在他的 Machine Learning 課程里用 matlab/octave ,而不用 python 或其他的語言的原因吧。
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
6819瀏覽量
88743 -
矩陣
+關(guān)注
關(guān)注
0文章
418瀏覽量
34475 -
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8353瀏覽量
132315
原文標(biāo)題:Numpy 隱含的四大陷阱,千萬別掉進(jìn)去了!
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論