1. 程式人生 > >與機器學習演算法有關的資料結構

與機器學習演算法有關的資料結構

摘要: 在機器學習中需要運用到許多資料結構,掌握它們是非常重要的。希望本文能有所幫助

擁有機器學習技能是不夠的。你還需要良好的資料結構的工作知識。學習更多,並解決一些問題。

因此,你已經決定不再使用固定的演算法並開始編寫自己的機器學習方法。也許你已經有了一種新的叢集資料的新方法,或者你可能對你最喜歡的統計分類包的侷限性感到失望。

無論哪種情況,你對資料結構和演算法的瞭解越多,在程式碼編寫時就越容易。

我不認為機器學習中使用的資料結構與其他軟體開發領域的資料結構有很大的不同。然而,由於許多問題的規模和難度,對基礎知識的掌握非常重要。

另外,由於機器學習是一個數學性非常強的領域,我們應該記住,資料結構是如何被用來解決數學問題的,以及它們是如何以自己的方式來處理數學問題的。

有兩種方法可以對資料結構進行分類:通過它們的實現和它們的操作。

通過實現,我指的是它們的程式設計方式和實際儲存模式的具體細節。它們的外觀並沒有如何實現更重要。對於按操作或抽象資料型別分類的資料結構來說,情況恰恰相反——它們的外觀和操作比實現方式更重要,事實上,它們通常可以使用許多不同的內部表示來實現。

陣列

當我說基本陣列是機器學習中最重要的資料結構時,我並不是在開玩笑。這個實用的型別比你想象的要多。陣列非常重要,因為它們被用於線性代數——這是你可以使用的最有用和最強大的數學工具。

因此,最常見的型別分別是一個和二維的型別,分別對應於向量和矩陣,但偶爾會遇到三個或四維的陣列,它們要麼用於更高級別的張量,要麼為前者的組示例。

在進行矩陣運算時,你將不得不從令人眼花繚亂的各種庫、資料型別、甚至語言中進行選擇。許多科學程式語言,如Matlab,互動式資料語言(IDL),以及帶有Numpy擴充套件的Python,主要是為處理向量和矩陣而設計的。

但這些資料結構的優點是,即使在更通用的程式語言中,實現向量和矩陣在metal很簡單,假設語言中有任何Fortran DNA。考慮矩陣向量乘法的平移:

使用C++:

for (int i=0; i<n; i++) {

  y[i]=0;

  for (int j=0; j<n; j++) y[i]+=a[i][j]*x[j]

}

在大多數情況下,陣列可以在執行時分配到固定大小,或者可以計算可靠的上限。在那些需要陣列無限擴充套件的情況下,可以使用可擴充套件陣列,例如C ++標準模板庫(STL)中的vector類。Matlab中的規則陣列具有相似的可擴充套件性,可擴充套件陣列是整個Python語言的基礎。

在這個資料結構中,有兩個元資料與實際資料值一起儲存。 這些是分配給資料結構的儲存空間量和陣列的實際大小。一旦陣列大小超過儲存空間,將分配一個新空間,該空間的大小是其大小的兩倍,將值複製到其中,並刪除舊陣列。

這有一個O(n)操作,其中n是陣列的大小,但由於它只是偶爾發生,所以新增一個新值到實際結束的時間實際上被分配到常量時間O(1)。這是一個非常靈活的資料結構,具有快速的平均插入和快速訪問。

可擴充套件陣列非常適合組成其他更復雜的資料結構並使其可擴充套件。例如,要儲存稀疏矩陣,可以在結尾新增任意數量的新元素,然後按位置對其進行排序以更快地定位。稍後詳述!

連結串列

連結串列由幾個分開分配的節點組成。每個節點都包含一個數據值和一個指向列表中下一個節點的指標。插入在不變的時間是非常有效的,但是訪問一個值很慢,並且通常需要掃描大部分列表。

連結串列很容易拼接並分開。有許多變化——例如,可以在頭部或尾部進行插入;該列表可以是雙鏈接的,並且有許多類似的資料結構基於相同的原則。

主要是,我發現連結串列可用於解析不確定長度的列表。 之後,它們可以轉換為固定長度的陣列以便快速訪問。出於這個原因,我使用了一個連結列表類,其中包含一個轉換為陣列的方法。

二叉樹

二叉樹與連結串列相似,只不過每個節點都有兩個指向後續節點的指標而不是一個。左側孩子的值總是小於父節點的值,而父節點的值又小於右側孩子的值。因此,二叉樹中的資料會自動排序。O(log n)的平均插入和訪問都是有效的。像連結列表一樣,它們很容易轉換為陣列,這是樹狀排序的基礎。

平衡樹

如果資料已經排序,二叉樹在O(n)最差的情況下效率較低,因為資料將被線性排列,就好像它是一個連結串列。雖然二叉樹中的排序受到限制,但它絕不是唯一的,並且可以根據插入的順序以相同的列表排列許多不同的配置。

為了使其更加平衡,可以將一些轉換應用於樹。自平衡樹會自動執行這些操作,以保持訪問和插入的最佳平均值。

機器學習中普遍存在的問題是找到最接近某一特定點的鄰居。這個問題是NN演算法所需要的。KD樹是一種二叉樹,它提供了一種有效的解決方案。

堆是另一個層次結構,類似於樹的有序資料結構,它具有垂直排序,而不是水平排序。這種排序適用於層次結構,但不適用於整個層次:父節點總是大於它的子節點,但是更高級別的節點並不一定比下面的節點要大。

插入和檢索都是通過升級來執行的。元素首先插入到最高可用位置。然後將其與其父母進行比較並提升,直至達到正確的等級。為了從堆中去掉一個元素,兩個孩子中較大的一個被提升到缺失的位置,然後這兩個孩子中較大的一個被提升,如此等等,直到每一個都變成正確的等級。

通常情況下,頂部的最高排名值將從堆中取出,以便對列表進行排序。 與樹不同,大多數堆只是簡單地儲存在陣列中,元素之間的關係只是隱含的。

堆疊

一個堆疊被定義為“先進後出”。一個元素被壓入堆疊的頂部,覆蓋前一個元素。頂部的元素必須先彈出才能訪問任何其他元素。

堆疊主要用於解析語法和實現計算機語言。

在許多機器學習應用程式中,領域特定語言(DSL)是完美的解決方案。例如,libAGF庫使用遞迴控制語言將二進位制分類一般化到多類。特殊字元用於重複前面的選項,但是由於語言是遞迴的,所以必須從相同的層次或更高的層次上選擇該選項。這是由堆疊實現的

佇列

佇列被定義為“先入先出”。想想銀行櫃員面前的隊伍(對於我們這些年紀還大的人來說,還記得在網上銀行出現之前的一段時間)。佇列在實時程式設計中非常有用,因此程式可以維護要處理的作業列表。

考慮一個記錄運動員分段時間的應用程式。你輸入bib號碼,然後按回車鍵,但你要做的時候,後面的運動員也通過了。所以你輸入的是最近接近運動員的bib號碼列表,然後按下一個單獨的鍵來註冊佇列中的下一個。

集合

一個集合包含一個非重複元素的無序列表。如果新增已經在集合中的元素,則不會有任何更改。由於機器學習的許多數學知識都與集合有關,所以它們是非常有用的資料結構。

關聯陣列

在關聯陣列中,有兩種型別的資料成對儲存:金鑰及其相關值。 資料結構本質上是關係型的:數值由其鍵來解決。由於大部分訓練資料也是關係型的,這種型別的資料結構似乎非常適合於機器學習問題。

在實踐中,它的用處不大,部分原因是大多數關聯陣列只是一維的,而機器學習資料通常是多維的。

關聯陣列適用於構建字典。

假設你正在構建一個DSL,想要儲存一個函式和變數列表,並且需要區分這兩者。

  • sin =函式。
  • var = 變數。
  • exp =函式。
  • x =變數。
  • sqrt =函式。
  • a =變數。

在“sqrt”查詢陣列將返回“函式”。

自定義資料結構

當你處理更多問題時,你肯定會遇到標準配方框不包含最佳結構的那些問題。你將需要設計自己的資料結構。

考慮一個多類分類器,它概括了一個二元分類器來處理具有兩個以上類的分類問題。一個明顯的解決方案是平分:遞迴地將類分成兩組。但分層解決方案並不是解決多類的唯一方法,你可以使用類似於二叉樹的方法來組織二進位制分類器。

考慮幾個分割槽,然後用它們同時解決所有類的概率。

最通用的解決方案將兩者結合起來,因此每個分層分割槽不需要是二進位制的,而是可以通過非分層多類分類器來解決。這是在libAGF庫中採用的方法。

更復雜的資料結構也可以由基本結構組成。考慮一個稀疏矩陣類。在稀疏矩陣中,大多數元素都是零,並且只儲存非零元素。我們可以將每個元素的位置和值儲存為一個三元組,並將它們的列表儲存在一個可擴充套件陣列中。

結論

資料結構本身偶爾也很有趣。令它們真正有趣的是它們可以解決的各種問題。

對於大多數工作,我使用了許多基本的固定長度陣列。我主要使用更復雜的資料結構來使程式在執行和與外部介面互動方面更加流暢,並且更加便於使用者使用。不像以前的Fortran程式那樣,為了改變網格大小,我不得不忍受一個接近半小時的編譯週期(我實際上在這樣的程式上工作過!)。

即使你無法想出一個應用程式,我仍然認為知道諸如棧和佇列之類的東西是件好事。你永遠不知道什麼時候會派上用場。

真正複雜的人工智慧應用程式可能會使用定向和無向圖,它們只是樹和連結串列的一般化。如果你無法應對後者,你將如何建立起像前者那樣的東西?

問題

如果你想自己練習和實現ML演算法的資料結構,請嘗試解決下面的一些問題:

  1. 將矩陣向量乘法程式碼片段封裝到名為matrix_times_vector的子例程中。設計子例程的呼叫語法。
  2. 使用structtypedefclass,將向量和矩陣分別封裝到一對稱為vectmatrix的抽象型別中。為這些型別設計一個API
  3. 在網上找到至少三個以上的庫。
  4. 下載並安裝LIBSVM庫。考慮方法Kernel :: k_function在“svm.cpp”的第316行。用於儲存向量的資料結構有哪些優缺點?
  5. LIBSVM庫中,如何重構核心函式的計算?
  6. 文中描述的哪些資料結構是抽象型別?
  7. 你可以使用什麼內部表示/資料結構來實現抽象資料型別?上面的列表中是否有未包含的內容?
  8. 使用二叉樹,設計一個關聯陣列。
  9. LIBSVM中考慮向量型別。如何用它來表示一個稀疏矩陣?與上面描述的稀疏矩陣類進行對比。看看完整的型別。每個代表的優點和缺點是什麼?
  10. 實現一個treesort和一個堆排序。現在使用相同的資料結構來查詢前k個元素。什麼常見的機器學習演算法適合這種情況?
  11. 用你喜歡的語言實現你最喜歡的資料結構。
作者資訊

Luba Belokon 市場營銷人員,Peter Mills 研究科學家

文章原標題《Data Structures Related to Machine Learning Algorithms

作者:Luba Belokon,Peter Mills譯者:董昭男 稽核:

原文連結

閱讀更多幹貨好文,請關注掃描以下二維碼: