[翻譯] NumSharp的陣列切片功能 [:]

solenovex發表於2019-05-26

原文地址:https://medium.com/scisharp/slicing-in-numsharp-e56c46826630

 

翻譯初稿(英文水平有限,請多包涵):

由於Numsharp新推出了陣列切片這個牛逼的功能,所以.NET社群距離擁有強大的開源機器學習平臺又近了一步。  
  
Python之所以是機器學習的首選語言,部分原因就是因為它擁有一些牛逼的庫,例如NumPyTensorflow與此同時,C#開發人員也迫切需要用於機器學習和資料科學的強大開源庫。而NumSharp這個由 SciSharp STACK這個開源組織全力推動的,要把NumPy移植到C#的這個專案,由於其最近全面實現了切片技術,從而向該目標邁進了一大步。該技術允許對n維陣列隨意的建立子集,並將其作為對原始資料的高效檢視。因為這些,使得它與TensorFlow.net一起成為了C#中機器學習的有用工具。  

  

到底有啥大不了的?  

如果你沒用過NumPy,你可能不知道切片技術有多好用, Python陣列允許通過對一定範圍對元素進行索引來返回陣列的一個切片,其索引操作是這樣的:a[start:end:step]。但是,只有使用NumPy複雜巧妙的陣列實現,切片才成為一種真正強大的資料操作技術,若沒有這種技術,機器學習或資料科學就無法想象了。  

  

對於那些不能或不想因為機器學習就轉換到Python語言的人來說,幸運的事情發生了,我對此也很羨慕, NumSharp將這種能力帶入了.NET世界裡。作為NumSharp的開發人員之一,我將向您展示幾個重要的切片用例,並附有C#的示例程式碼段。首先請注意,由於語言語法的不同,在C#中無法以與Python相同的方式進行索引。但是,我們決定保留Python裡切片定義的語法,因此在C#裡,我們使用字串來索引切片。   

 

 

而使用NumSharp寫出的C#程式碼也是差不多一樣的。但請注意,這裡有一個細微的差別是,這裡的切片使用的是字串作為索引器的引數進行的索引。 

  

正如您所看到的,NumSharp團隊花了很多的精力來保證程式碼儘可能的與Python相似。 這非常重要,因為這樣的話,現有的依賴於NumPy的程式碼就可以很輕鬆的移植到C#上去了。 

 

用例使用同一資料的多個檢視 

對於執行時效能,尤其是對於大規模的資料集而言,能夠在不進行復制的情況下僅對函式傳入和傳出原始資料的本地部分(例如:一張大圖片中的一部分)是至關重要的。切片使用區域性座標進行索引的,因此您的演算法無需瞭解資料的全域性結構,這樣就有效地簡化了您的工作,並確保儘可能高的效能,因為避免了不必要的複製。 

 

用例:稀疏檢視和遞迴切片  

除了對切片的範圍指定startend之外,再通過指定它的步長,就可以建立陣列的稀疏檢視了。這是一個連C# 8.0新的陣列切片語法都沒有的功能(據我所知)。在使用交錯資料時,此功能變得非常重要。您可以通過設計演算法來讓它們處理連的續資料併為它們提供模擬連續資料來源的稀疏切片,從而儘可能降低演算法的複雜性。 

切片可以進一步切片,如果您使用高維資料的話,這也將是一個非常重要的功能。同時這也有助於減少演算法的複雜性,因為通過遞迴切片減少了資料的維數。 

 

用例:高效地處理高維資料 

如果您需要將資料陣列視為一個卷,並在不需要進行令人煩躁的座標轉換計算的情況下使用其中的某些部分,那麼.reshape()方法就是您的朋友。 

所有由.reshape()或切片操作建立的陣列都只是原始資料的檢視。當您對檢視的元素進行迭代、讀取或寫入時,其實您訪問的是原始的資料陣列。很顯然,NumSharp為您做了相應的索引變換,所以您可以使用相對的座標對切片進行索引。 

 

用例:在無任何額外成本的情況下顛倒元素的順序 

使用值為負數的步長可以高效的反轉切片的順序。它的優點是不需要複製或列舉資料就可以完成此操作,就像IEnumerable.Reverse() 一樣。區別在於,檢視(就是指a["::-1"]的操作結果)以相反的順序顯示資料,此外您無需對其進行列舉就可以索引到該反轉序列。 

 

用例:通過減少維度來降低複雜性 

當處理高維資料時,該資料的演算法也會變得非常複雜。在處理NumSharpNDArray.ToString() 方法時(這個方法可以列印出任意高維卷)我注意到該演算法通過系統地和遞迴地將(N-1)D卷切出ND-卷等諸如此類的方式簡單而優雅的取得了結果。 

通過在可返回低維子卷的範圍符號上使用NumSharp的索引符號進行切片,才使這種分而治之的方法變得可行。 

  

範圍符號 vs 索引符號 

範圍符號[“start:stop:step”]允許您訪問具有相同維度給定卷的子範圍。所以即使只劃出二維矩陣的一列,仍然可以得到只有一列的二維矩陣。下面這一小段C#程式碼就展示了這一點: 

陣列字元索引過載可以實現在一個N維陣列裡從特定位置建立檢視。因此,用索引符號從二維矩陣中分割出一個列,可以得到一個一維向量: 

如果您一眼也沒有發現差異,那麼下面這兩個切片定義, ange [":,2:3"] vs index [":,2"],它們的結果是大不相同的。NumSharp wiki提供了新切片表示法的完整參考 

 

附註:ArraySlice <T> 

在實現N維檢視的切片時,我得出這樣一個結論,對於.NET中的許多其他領域來說它可能很有趣,因此我將它分解出一個自己的獨立庫SliceAndDice它裡面有個東西叫做ArraySlice <T>,它是對所有索引的C#資料結構(如T[]IList<T>)的一個輕量級包裝,此外它還允許您使用相同的塑形,切片和檢視機制,並且無需進行任何其他的重度數值計算。它只使用了幾百行程式碼就漂亮簡潔的完成了切片的壯舉。 

  

綜上

NumSharp最近被賦予了切片和檢視機制,同樣就是這些機制讓NumPy成為Python機器學習生態最重要的庫之一。SciSharp Stack作為一個開源組織,目前只有少數技術嫻熟的開發人員,但他們卻非常努力地要為.NET世界帶來同樣的魔力。NumSharp最近的這次改進就是實現這一目標的重要基石。 

相關文章