工程師要理解機器學習算法的複雜性

本文闡述了理解機器學習算法內部工作原理的重要性,以及它在實現和評估方面的不同之處。

機器學習工程師經常會發現,他們總是需要爲手頭的問題選擇正確的算法。通常情況下是這樣做的:首先,他們需要了解他們提供解決方案的問題的結構。然後,他們研究手頭的數據集。經過初步觀察後得到關鍵結論,最終,他們爲任務選擇正確的算法。

確定適用於手頭數據集的最佳算法似乎是一項普通的工作。通常在這種情況下,工程師們會試圖走捷徑。如果任務有 0-1 標籤,那麼只需應用邏輯迴歸就可以了,對嗎?不對!我們應該意識到這些捷徑,並時刻提醒自己,儘管某些算法可以很好地解決特定問題,但是,爲解決問題選擇最佳算法時,卻沒有什麼訣竅。然而,工程師們應該始終討論並考慮算法的複雜性和運行時分析。

算法的運行時分析不僅對理解算法的內部工作至關重要,而且還可以產生更爲成功的實現。

在本文中,我將描述一種情況,在這一情況下,忽略算法的運行時分析,K 表示聚類,這些都是會讓工程師浪費大量的時間和精力的東西。

什麼是 K 均值聚類

K 均值聚類(K-means clustering)是目前最流行、最容易實現的無監督機器學習算法之一。它也是一種易於理解的機器學習算法。

通常情況下,無監督機器學習算法僅使用特徵向量對輸入數據集中做出推理(Inferences)。因此,這些算法適用於沒有標籤數據的數據集。當人們想從大量結構化和非結構化數據中提取價值或洞見時,它們也非常有用。K 均值聚類是其中一種探索性數據分析技術,其目標是提取數據點的子羣(subgroup),以使同一聚類中的數據點在定義的特徵方面非常相似。

K 均值聚類的工作原理

K 均值聚類算法是從隨機選擇的第一組數據點開始,這些數據點被用作質心(Centroid)的初始種子。然後,該算法執行迭代計算,將其餘的數據點分配給最近鄰的聚類。當根據定義的距離函數執行這些計算時,質心的位置將會更新。在以下任一情況下,它都會停止對聚類中心的優化:

  • 質心的位置是穩定的,即,它們的值的變化不超過預定義的閾值。
  • 該算法超過了最大迭代次數。

因此,該算法的複雜度爲:

O(n * K * I * d)
n : number of points
K : number of clusters
I : number of iterations
d : number of attributes

K 均值算法示例問題

我將分享一段 K 均值聚類算法任務的代碼段。我唯一目的在於爲讀者演示一個示例,在這個實例中,如果不能理解運行時的複雜性,那麼將會導致對算法的評估很差勁。需要說明的是,我所採取的步驟並沒有針對算法進行優化,也就是說,爲了取得更好的結果,你可以對數據進行預處理並獲得更好的聚類。所涉及的步驟概述如下:

  1. 導入庫,並讀取數據集。在這個示例中,我導入相關的庫並讀書數據集,這些數據集已經下載到本地文件夾中。
  2. 預處理。在這一步中,我丟棄了字符串類型的列,而只關注數值特性。由於 K 均值聚類算法計算數據點之間的距離,所以它適用於數值列。
  3. 應用主成分分析法進行降維。在應用 K 均值聚類算法之前,最好先對數據集進行降維,因爲在高維空間中,距離度量的效果並不是很好。
  4. 計算輪廓分數。K 均值聚類算法並不能直接應用。它涉及到尋找聚類最佳數量的問題。輪廓分數(Silhouette score)是可以用來確定聚類最佳數量的技術之一。如果不能理解輪廓分數分析所涉及的計算的複雜性,將會得到較差的實現效果。
  5. 其他解決方案。在本文中,我列出了一些可供選擇的解決方案,以找到聚類的最佳數量。在運行時複雜性方面,它們與輪廓分數相比,更具優勢。

你可以重現這個問題來親自嘗試。數據集的地址爲:https://www.kaggle.com/sobhanmoosavi/us-accidents。

第一步:導入庫並讀取數據庫

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
from sklearn.cluster import KMeans
from sklearn import metrics
df = pd.read_csv(file)

第二步:預處理

#Remove columns that have almost all of its value as None
df.drop(['End_Lat','End_Lng','Number','Wind_Chill(F)','Precipitation(in)'],inplace = True,axis=1)
#Change type of boolean columns to integer
for column in df.columns.values:
    if df[column].dtype == bool:
        df[column] = df[column].astype(int)
def handleMissingData(data): 
  for column in data.columns.values:
    if column not in ['ID'] and data[column].isna().sum():
      if data[column].dtype == int or data[column].dtype == float:
        data[column].fillna(data[column].mean(),inplace=True)
      else:
        data[column].fillna(data[column].mode()[0],inplace=True)
handleMissingData(df)
df = df[['Amenity','Crossing','Junction','No_Exit','Railway','Station','Stop','Traffic_Signal']]
handleMissingData(df)
df = df[['Amenity','Crossing','Junction','No_Exit','Railway','Station','Stop','Traffic_Signal']]

我們只根據與路徑有關的特徵對數據點進行聚類,以便進行說明。

第三步:應用主成分分析進行降維

import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
from sklearn.decomposition import PCA
data_points = df[df.columns.values].values
numberOfPCAComponent = 3
pcaComponents = []
for i in range(numberOfPCAComponent):
    pcaComponents.append("PCA"+"_"+str(i+1))
component_pos = np.arange(len(pcaComponents))
sklearn_pca = PCA(n_components=numberOfPCAComponent)
sklearn_pca1 = PCA()
sklearn_pca1.fit(data_points)
data_points = sklearn_pca.fit_transform(data_points)
explained_variance = sklearn_pca.explained_variance_ratio_  
print(explained_variance,"explained_variance")
plt.bar(component_pos, explained_variance, align='center', alpha=0.5)
plt.xticks(component_pos, pcaComponents)
plt.ylabel('Explained Variance')
plt.title('Principle Components')
plt.show()
plt.savefig('explained_variance.png')
plt.plot(range(0,8), sklearn_pca1.explained_variance_, 'bx-')
plt.xlabel('pca component')
plt.ylabel('explained variances')
plt.title('Elbow Method For Optimal Number of PCA Component')
plt.show()
plt.savefig('elbow_method_optimal_number_pca.png')
pickle.dump(sklearn_pca,open("pca_stage_semi-supervised.pkl","wb"))

看起來 3 是最佳的。

第四步:計算輪廓得分

確定最佳聚類數目有許多指標和方法。但我會集中討論其中的幾個。輪廓得分就是這些指標度量之一。它使用每個實例的平均聚類內距離和平均最近鄰聚類距離來計算的。它計算每個樣本和相應聚類中其餘樣本之間的距離。因此,它的運行時複雜度爲 O(n²)。如果無法執行運行時分析的話,你可能需要等待數小時(如果不是數天)才能完成對大型數據集的分析。由於當前數據集有數百萬行,解決方法可以是使用更簡單的指標度量,如慣性或對數據集應用隨機採樣。我將闡述這兩種方法。

備選解決方案

  • 肘部法則

該方法使用慣性或聚類內平方和作爲輸入。它描述了慣性值隨聚類數量的增加而減小的情況。“肘部”(Elbow,曲線上的拐點)就是一個很好的指示點,在該點上慣性值的減小並不會發生明顯的變化。使用這種技術的優點是,聚類內平方和在計算上不像輪廓得分那樣昂貴,並且已經作爲度量包含在算法中。

%%timeit 
from sklearn.cluster import KMeans
from sklearn import metrics
Sum_of_squared_distances = []
K = range(2,6)
for k in K:
    km = KMeans(n_clusters=k,random_state=5)
    km = km.fit(data_points)
    Sum_of_squared_distances.append(km.inertia_)

上面這段代碼的掛鐘時間是:

27.9 s ± 247 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • 隨機降採樣

降採樣允許你可以處理更小的數據集。這樣做的好處是,算法完成所需的時間大爲減少。如此一來,分析人員就能夠更快地進行工作。缺點是降採樣如果隨機進行的話,可能無法代表原始數據集。因此,任何涉及降採樣數據集的分析都可能導致不準確的結果。但是,你始終可以採取預防措施來確保降採樣的數據集代表原始數據集。

%%timeit
from sklearn.cluster import KMeans
from sklearn import metrics
#apply k means clustering and measure silhouette score 
kmeans = KMeans(n_clusters=4,random_state=5).fit(data_points)
metrics.silhouette_score(data_points,kmeans.labels_,metric='euclidean',sample_size=100000)

上面代碼段的掛鐘時間爲:

3min 25s ± 640 ms per loop (mean ± std. dev. of 2 runs, 1 loop each)

結語

在本文中,我試圖強調理解機器學習算法複雜性的重要性。算法的運行時分析不僅對於特定任務中的算法選擇至關重要,而且對算法的成功實現也很重要。這也是大多數僱主在數據科學領域中尋找的關鍵技能之一。因此,進行運行時分析並理解算法的複雜性,一直就是很好的實踐。

作者介紹:

Baran Köseoğlu,軟件開發人員,數據科學家。對機器學習、人工智能和數據科學感興趣。著有《Towards Data Science》一書。

原文鏈接:

https://towardsdatascience.com/importance-of-understanding-the-complexity-of-a-machine-learning-algorithm-9d0532685982

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章