首頁>技術>

介紹

在過去幾年資料科學技術的飛速發展中,我們看到大量開源工具的急劇升級和採用。其中包括一些熱門工具,如SkLearn和Tensorflow。

然而最近隨著Julia的流行,我們有機會大大改進解決機器學習問題的方法。對Julia語言影響最大的問題就是缺少成熟的各種資料相關操作的包。

這將是一條漫長的道路。我們先看看Julia在目前的狀態下所能提供的功能。最近讓我很驚喜的一個新功能是我們的專案上增加了一個隨機森林分類器。使用Lathe、資料幀和CSV,我們現在可以輕鬆地探索、編碼和預測各種特徵!

資料

為了使用機器學習模型,我們首先需要看一下獲取一些分類資料來訓練它。

在這個例子中,我將使用一些加州大學洛杉磯分校釋出的歐洲汽車資料。由於資料是逗號分隔值(CSV)格式,我們將使用 CSV.jl庫。Julia生態系統的一個奇妙的屬性是分割的程度。CSV.jl是專門為讀取CSV.jl而開發的軟體包,它返回一個數據幀。JSON.jl是專門為讀取JSON格式資料而開發的包。我們還想匯入DataFrames,這將使電子表格中能顯示實際資料。

using DataFramesusing CSV

現在我將讀取CSV檔案:

df = CSV.read("car data.csv")

在不久的將來,這種讀取.CSV檔案的方法將被棄用,因此最好使用sink引數:

using DataFrames; df = CSV.read("car data.csv", DataFrame)

獲取資料幀的最佳檢視的最簡單方法是使用show方法。為了更好地視覺化特徵,我們可以使用allcols關鍵字引數,它將採用Bool型別:

show(df, allcols = true)

考慮到這裡的目的是演示,除了對這個應用程式有用的特徵之外,不會對這些特徵進行太多的考慮。為了檢視唯一的類別,我們可以使用Set型別:

Set(df[!, :Transmission])

考慮到基於基尼指數的模型,像這樣的分類器,去除雜質特徵通常做得更好,我選擇燃料型別作為目標。

至於這個應用程式中的特徵,我決定使用一個連續的特徵,因為只有一組0和1作為特徵很難預測。

我決定做的第一件事是將我想使用的這兩個特徵提取到一個新的更小的資料幀中,如下所示:

mldf = DataFrame(:Fuel => df[!, :Fuel_Type], :Kms => df[!, :Kms_Driven])
預處理

使用任何模型的一個重要步驟是預處理和評估。在這裡,你可能想問一個模型是否真的可以幫助解決這個問題。這可以用一個多分類的基線來完成。多分類基線是一種簡單的度量方法的有效性,它可以為每個場景猜測最常見的類別。

讓我們從評估開始。解決這個問題的第一步可能是將我們的資料放入簡單的一維陣列中,這些陣列可以放入一些函式中。我喜歡用符號和資料幀呼叫來實現這一點:

X = :KmsY = :Fuel

接下來,我們將把資料分為一個訓練和一個測試集。因此,我們既有資料來訓練模型,也有資料來獲得可靠的評估。為此,我們將使用Lathe.jl:

using Lathe.preprocess: TrainTestSplittrain, test = TrainTestSplit(mldf)

現在有兩個資料幀,train和test,我們可以從中提取一維陣列。

trainX = train[!, X]trainy = train[!, Y]testX = test[!, X]testy = test[!, Y]

接下來,我們將獲得多分類的基線:

using Lathe.models: majClassBaseline

因為這是Julia,所以可以使用?()方法:

如文件所示,該函式接受一個引數y,並將返回一個Lathe模型物件。這個物件將有函式predict,我們可以用它來返回一個預測。透過提供trainy建立該物件,然後使用testX進行預測:

evaluation = majClassBaseline(trainy)yhat = evaluation.predict(testX)

如你所見,這些汽車中最常見的燃料顯然是汽油。我們使用Lathe.lstats的catacc函式:

using Lathe.lstats: catacccatacc(yhat, testy)

對於這個測試,81%是一個相當高的準確度水平,通常這樣的問題甚至不需要一個模型來解決,而僅僅是一個假設。也就是說,我們來這裡是為了安裝一個隨機森林分類器,這就是我們要做的!另一件很酷的事情是我們可以看基線模型裡面的計數,這可能會讓我們深入瞭解為什麼準確度如此之高:

evaluation.counts()

擬合與評估

我們要處理的模型是Lathe.models的RandomForestClassifier:

using Lathe.models: RandomForestClassifier

像以前一樣,可以用?()方法,以便檢視有關此特定物件的程式碼內文件:

如文件所示,該模型同時接受關鍵字引數和位置引數作為輸入。我們的第一個模型將簡單地提供X和Y作為引數。

model = RandomForestClassifier(trainX, trainy)

現在可以繼續進行評估,就像我們對大多數類基線所做的那樣:

yhat = model.predict(testX)

並使用catacc進行評估:

正如我之前所說的,這當然不是這個模型的最佳,但是可以做一些簡單而有趣的嘗試來提高這種準確性。

首先,由於類別的數量很少,max_depth值為6可能過擬合。為了驗證這個理論,先給它一個提升,然後再降低。如果這個懷疑是正確的,那麼把它提高很可能會導致準確性的嚴重下降:

model = RandomForestClassifier(trainX, trainy, n_trees = 100, max_depth = 11)yhat = model.predict(testX)

同樣,降低引數會導致相反的結果:

model = RandomForestClassifier(trainX, trainy, n_trees = 100, max_depth = 2)yhat = model.predict(testX)

雖然最基本的反應可能是降低深度,以這種方式處理模型,但我認為如果有一個關於深度稍微加深,樹再更多的話,模型可能會做得更好:

model = RandomForestClassifier(trainX, trainy, n_trees = 1000, max_depth = 5)yhat = model.predict(testX)

好極了!稍加調整,我們的模型已經大大提高了準確性!最後一個技巧是,可以嘗試擴充套件特徵。為此我們將使用Lathe.preprocess:

scaler = StandardScaler(trainX)trainX = scaler.predict(trainX)

接下來,我們將在testX上執行相同的程式:

testX = scaler.predict(testX)

這會返回一個複數陣列。為了修正它們的虛邊界,可以使用real()方法將資料更改回實數。當然,這需要被繫結到整個陣列上,所以可以透過改變陣列內的資料型別來實現:

trainX = Array{Real}(trainX)testX = Array{Real}(testX)

現在透過與之前相同的程式碼,我們可以看到這是否進一步提高了精確度:

model = RandomForestClassifier(trainX, trainy, n_trees = 1500, max_depth = 5)yhat = model.predict(testX)catacc(yhat, testy)

它失去了準確性嗎?

請允許我解釋一下。每當使用對資料進行標準化處理時,就會減少問題的難度,因為我們將觀測值計算為標準差(均值),因為特徵都被標準化到一個某個範圍裡了。也就是說,我們的精度增益可以透過快速調整深度來感覺到:

model = RandomForestClassifier(trainX, trainy, n_trees = 1500, max_depth = 3)yhat = model.predict(testX)

經過一些超引數最佳化,結果如下:

model = RandomForestClassifier(trainX, trainy, n_trees = 10, max_depth = 2, min_node_records = 4)yhat = model.predict(testX)catacc(yhat, testy)

結論

在Julia的生態系統中,分類問題已經有一段時間了。幸運的是,由於許多Julia包的進一步開發,有許多方法可以在Julia中非常有效地獲得相當準確的分類預測。

8
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 使用CSS Flexbox 構建可靠實用的網站 Header