標籤:

Matlab如何對二維數據分類

時常會去回顧自己以前寫的帖子,相信這些帖子不僅僅是寫給公眾號的朋友,同樣也是提醒與鼓勵自己。尤其是讀到先前的一篇帖子「多思考,因為努力是從來不會騙人的」,而對於這句話,尤為感觸。每完成一段代碼,不敢輕易斷言代碼的邏輯最優,每過去一段時間,總會有新的思路,來優化這段代碼。引用論語的一段話:「吾日三省吾身;為人謀而不忠乎?與朋友交而不信乎?傳不習乎?」。而傳不習乎指的就是要時時溫習舊經驗,求取新知識。

之所以會有這段感觸,是因為在過去的這個星期,發現了先前寫過的一段代碼略顯愚蠢。這段代碼最先源於一個工作上的任務,是對一個數據進行範圍上的歸類,並進行百分比計算,最終將結果分別以數值及顏色的方式輸出到Excel表中。當時寫過一篇帖子「不擅長Excel宏的人」,這篇帖子講述的是如何將結果輸出到Excel表,正是在這個任務中產生的。

而今天想聊的不是這部分代碼,而是如何對數據進行二維歸類。先來細化一下這個任務,數據的一維歸類,打個比方就是,對於一組數據,計算有多少個點分別在[0,5],[5,10],[10,15],……的區間。而二維歸類,以此類推就是,對於一組數據,計算有多少個點分別在A的[0,5]B的[0,5]的區間,A的[0,5]B的[5,10]的區間,A的[5,10]B的[0,5]的區間等等。

在第一次拿到這個任務時,由於時間緊迫,對於代碼邏輯並沒有細想,使用的是二維For循環,每次循環取相應緯度的區間,分別判斷數據中有多少點存在於這個區間中,如下面這段代碼所示:

這段代碼中所使用的是find函數去查找存在於目標區間中的數據。這段代碼的弊端十分明顯,就是耗時特別長。對於553萬3966*2的一個數據,耗時為85秒。

其中的原因在於,對於每個目標區間,都需要對原數據進行一次find處理。第一緯度的目標區間總計為75,第二緯度的目標區間總計為8,兩層的For循環,總計75*8=600次循環,而每次循環過程中有兩次find例遍原數據,而原數據又是百萬級別的數據。這個工作量可想而知,耗時85秒也是絲毫都不意外。

本以為在這個任務結束之後,我將不會再接觸這個任務。結果上個禮拜,又有新的數據發過來了,更頭疼的是,這次需要處理40個同級別大小的數據。換做先前的代碼,處理完這個任務需要將近一個小時的時間。但是為了避免今後再接到不計其數的相同的任務,於是我就重新優化了這個代碼。計算耗時結果如下

其中載入一個數據耗時0.7秒,數據處理耗時0.7秒,錄入Excel耗時3.2秒,總時長為4.6秒,單個數據文件處理速度提升了將近19倍。

我對這個代碼做了什麼?

正如上述的分析,我認為原先的方法耗時的主要原因在於600次循環,每次循環中兩次find例遍原數據。相當於這個代碼做了1200次例遍。於是我就思考,有沒有將1200次降為1次的辦法,即使是二維數據。

最終實現了,接下來聊一聊整個思路。首先將整體數據依據各自的維度進行標準化,打個比方,3屬於[0,5,10,15……]中的第一檔,用代碼顯示就是

Index = floor(data/delta)+offset

以上述為例,data=3,delta=5,而offset=1.最終結果為1。函數floor的作用就是求不超過目標量的最大整數。

對數據的兩個維度分別按各位的delta進行標準化處理,所得到的結果正是在矩陣中所對應的序號。此後一次例遍原數據,對矩陣結果進行疊加,如下段代碼所示:

從上面這個再簡單不過的例子可以看到,多花些許時間思考,工作效率提或許就因此提升好幾倍。

新的一周即將開始了,即使將要過年,也希望諸位每天的工作與生活都順心如意。期待與你們再會。

以上

如果你有興趣,歡迎關注我的微信公眾號「打浦橋程序員」,謝謝


推薦閱讀:

TAG:MATLAB |