HOWTO · NumPy
NumPy Shuffle 兩個陣列
Python 中可以使用三種主要方法對兩個對應的陣列進行 shuffle,分別是 sklearn.utils.shuffle() 函式、numpy.random.shuffle() 函式和 numpy.random.permutation() 函式。
本頁內容
打亂兩個相關陣列時,必須同步改變它們的列順序。如果一個陣列中的第 i 列對應到另一個陣列中的第 i 列,例如特徵列及其標籤,兩個陣列就必須使用相同的排列順序。若分別打亂,這種對應關係就會被破壞。以下範例使用雙欄特徵陣列和標籤陣列;每列中相符的值能清楚呈現兩者如何對齊。
同步打亂兩個陣列,保留對應列的關係
對兩個陣列套用相同的列順序。每個輸入陣列的第一個維度長度必須相同。若陣列有多個欄位,共用的順序會選取完整的列,因此列中的值會保持在一起。
使用固定順序執行此範例,方便檢查相符的特徵列與標籤:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import numpy as np
features = np.array([[10, 100], [20, 200], [30, 300]])
labels = np.array([1, 2, 3])
order = np.array([2, 0, 1])
print(features[order])
print(labels[order])
[[ 30 300]
[ 10 100]
[ 20 200]]
[3 1 2]
此處使用固定順序只是為了示範;若要隨機排列,請使用下方其中一種打亂方法產生的順序。
使用 sklearn.utils.shuffle()
sklearn.utils.shuffle() 可以接收多個陣列,並對它們套用一致的排列順序,然後回傳打亂後的陣列供你指派使用。安裝 scikit-learn 後,先用 from sklearn.utils import shuffle 匯入函式,再呼叫 features_shuffled, labels_shuffled = shuffle(features, labels)。將所有相關陣列一併傳入同一次呼叫,回傳結果中的各列就會維持配對。若專案已使用 scikit-learn,這種方法會很方便。每次呼叫產生的隨機順序可能不同;這個函式會回傳結果供你指派,不會就地重新排列來源陣列。
匯入函式和呼叫它都需要 scikit-learn,而不是每個 Python 環境都安裝了這個套件。若環境中已安裝,請先執行匯入,再指派兩個回傳的陣列。這個需要特定相依套件的呼叫僅以語法形式展示,並未作為範例執行;下方的 NumPy 節提供不需要 scikit-learn、可執行的替代方法。
使用 NumPy 共用同一個排列順序
numpy.random.permutation(features.shape[0]) 會產生一組經過打亂的列索引。將它存入 order,再用 features[order] 和 labels[order] 選取資料。NumPy 的進階索引會產生索引後的結果,來源陣列仍保留原始順序。保留 order,即可再次使用完全相同的排列、將它套用到其他陣列,或與資料一起保存以供後續使用。產生並保留索引順序,也能避免依賴特定的隨機狀態介面。
此處只產生一組順序,並用它索引兩個陣列。輸出的列順序會變動,但特徵與標籤仍會保持配對:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import numpy as np
features = np.array([[10, 100], [20, 200], [30, 300]])
labels = np.array([1, 2, 3])
order = np.random.permutation(features.shape[0])
features_shuffled = features[order]
labels_shuffled = labels[order]
print(features_shuffled)
print(labels_shuffled)
使用 NumPy 打亂共用的索引陣列
numpy.random.shuffle() 會就地修改傳入的序列。使用 order = np.arange(features.shape[0]) 建立索引陣列,再以 np.random.shuffle(order) 打亂它,接著用 features[order] 和 labels[order] 選取兩個來源陣列的資料。這樣可以保留來源資料,同時明確指定列的順序。若有其他陣列,也可以使用相同做法:對每個需要對齊的陣列套用同一組打亂後的索引。只有 order 會被就地打亂;索引後的結果是另外產生的陣列。如果其他程式碼可能修改 order,而你之後仍需要保留這個排列,請先複製一份。
此範例只會修改 order;兩個來源陣列都使用同一組打亂後的索引:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import numpy as np
features = np.array([[10, 100], [20, 200], [30, 300]])
labels = np.array([1, 2, 3])
order = np.arange(features.shape[0])
np.random.shuffle(order)
features_shuffled = features[order]
labels_shuffled = labels[order]
print(features_shuffled)
print(labels_shuffled)
檢查形狀、變更行為與可重現性
陣列的第一個維度必須相容,也就是沿著 axis 0 的長度必須相同,但其餘維度可以不同。例如,特徵列矩陣可以搭配一維標籤陣列。套用索引順序前,先檢查各陣列的第一個維度大小,確保每個索引都適用於所有陣列。
三種方法修改的對象各不相同。sklearn.utils.shuffle() 會回傳打亂後的陣列供你指派。numpy.random.permutation() 會回傳一組新的索引順序;用它索引陣列便會產生重新排列的結果。numpy.random.shuffle() 會修改傳入的索引陣列;在這些範例中,它不會直接打亂來源陣列。無論使用哪種方法,只有讓所有相關陣列使用相同順序,才能維持彼此的對應關係。
若要重現相同排列,請保留產生的索引陣列,並再次將它套用到原始陣列,或將它與資料一起保存。重用相同的索引順序,就能重現相同排列,而不必依賴未指定的隨機狀態 API。若需要新的獨立排列,請重新產生一組順序。這些範例不保證會產生特定的輸出順序。