[譯] 機器學習能夠建模簡單的數學函數嗎?

機器學習能夠建模簡單的數學函數嗎?

使用機器學習建模一些基礎數學函數前端

近來,在各類任務上應用機器學習已經成爲了一個慣例。彷佛在每個 Gartner's 技術循環曲線 上的新興技術都對機器學習有所涉及,這是一種趨勢。這些算法被當作 figure-out-it-yourself 的模型:將任何類型的數據都分解爲一串特徵,應用一些黑盒的機器學習模型,對每一個模型求解並選擇結果最好的那個。python

可是機器學習真的能解決全部的問題嗎?仍是它只適用於一小部分的任務?在這篇文章中,咱們試圖回答一個更基本的問題,即機器學習可否推導出那些在平常生活中常常出現的數學關係。在這裏,我會嘗試使用一些流行的機器學習技術來擬合幾個基礎的函數,並觀察這些算法可否識別並建模這些基礎的數學關係。android

咱們將要嘗試的函數:ios

  • 線性函數
  • 指數函數
  • 對數函數
  • 冪函數
  • 模函數
  • 三角函數

將會用到的機器學習算法:git

  • XGBoost
  • 線性迴歸
  • 支持向量迴歸(SVR)
  • 決策樹
  • 隨機森林
  • 多層感知機(前饋神經網絡)

數據準備

我會保持因變量(譯者注:原文錯誤,應該爲自變量)的維度爲 4(選擇這個特殊的數字並無什麼緣由)。因此,X(自變量)和 Y(因變量)的關係爲:github

f :- 咱們將要擬合的函數算法

Epsilon:- 隨機噪聲(使 Y 更加真實一點,由於現實生活中的數據中老是存在一些噪聲)後端

每一個函數類型都會用到一系列的參數。這些參數經過生成隨機數獲得,方法以下:網絡

numpy.random.normal()
numpy.random.randint()
複製代碼

randint() 用於獲取冪函數的參數,以避免 Y 的值特別小。normal() 用於全部其餘狀況。dom

生成自變量(即 X):

function_type = 'Linear'

if function_type=='Logarithmic':
    X_train = abs(np.random.normal(loc=5, size=(1000, 4)))
    X_test = abs(np.random.normal(loc=5, size=(500, 4)))
else:
    X_train = np.random.normal(size=(1000, 4))
    X_test = np.random.normal(size=(500, 4))
複製代碼

對於對數函數,使用均值爲 5(均值遠大於方差)的正態分佈來避省得到負值。

獲取因變量(即 Y):

def get_Y(X, function_type, paras):
    X1 = X[:,0]
    X2 = X[:,1]
    X3 = X[:,2]
    X4 = X[:,3]
    if function_type=='Linear':
        [a0, a1, a2, a3, a4] = paras
        noise = np.random.normal(scale=(a1*X1).var(), size=X.shape[0])
        Y = a0+a1*X1+a2*X2+a3*X3+a4*X4+noise
    elif function_type=='Exponential':
        [a0, a1, a2, a3, a4] = paras
        noise = np.random.normal(scale=(a1*np.exp(X1)).var(), size=X.shape[0])
        Y = a0+a1*np.exp(X1)+a2*np.exp(X2)+a3*np.exp(X3)+a4*np.exp(X4)+noise
    elif function_type=='Logarithmic':
        [a0, a1, a2, a3, a4] = paras
        noise = np.random.normal(scale=(a1*np.log(X1)).var(), size=X.shape[0])
        Y = a0+a1*np.log(X1)+a2*np.log(X2)+a3*np.log(X3)+a4*np.log(X4)+noise
    elif function_type=='Power':
        [a0, a1, a2, a3, a4] = paras
        noise = np.random.normal(scale=np.power(X1,a1).var(), size=X.shape[0])
        Y = a0+np.power(X1,a1)+np.power(X2,a2)+np.power(X2,a2)+np.power(X3,a3)+np.power(X4,a4)+noise
    elif function_type=='Modulus':
        [a0, a1, a2, a3, a4] = paras
        noise = np.random.normal(scale=(a1*np.abs(X1)).var(), size=X.shape[0])
        Y = a0+a1*np.abs(X1)+a2*np.abs(X2)+a3*np.abs(X3)+a4*np.abs(X4)+noise
    elif function_type=='Sine':
        [a0, a1, b1, a2, b2, a3, b3, a4, b4] = paras
        noise = np.random.normal(scale=(a1*np.sin(X1)).var(), size=X.shape[0])
        Y = a0+a1*np.sin(X1)+b1*np.cos(X1)+a2*np.sin(X2)+b2*np.cos(X2)+a3*np.sin(X3)+b3*np.cos(X3)+a4*np.sin(X4)+b4*np.cos(X4)+noise
    else:
        print('Unknown function type')

    return Y


if function_type=='Linear':
    paras = [0.35526578, -0.85543226, -0.67566499, -1.97178384, -1.07461643]
    Y_train = get_Y(X_train, function_type, paras)
    Y_test = get_Y(X_test, function_type, paras)
elif function_type=='Exponential':
    paras = [ 0.15644562, -0.13978794, -1.8136447 ,  0.72604755, -0.65264939]
    Y_train = get_Y(X_train, function_type, paras)
    Y_test = get_Y(X_test, function_type, paras)
elif function_type=='Logarithmic':
    paras = [ 0.63278503, -0.7216328 , -0.02688884,  0.63856392,  0.5494543]
    Y_train = get_Y(X_train, function_type, paras)
    Y_test = get_Y(X_test, function_type, paras)
elif function_type=='Power':
    paras = [2, 2, 8, 9, 2]
    Y_train = get_Y(X_train, function_type, paras)
    Y_test = get_Y(X_test, function_type, paras)
elif function_type=='Modulus':
    paras = [ 0.15829356,  1.01611121, -0.3914764 , -0.21559318, -0.39467206]
    Y_train = get_Y(X_train, function_type, paras)
    Y_test = get_Y(X_test, function_type, paras)
elif function_type=='Sine':
    paras = [-2.44751615,  1.89845893,  1.78794848, -2.24497666, -1.34696884, 0.82485303,  0.95871345, -1.4847142 ,  0.67080158]
    Y_train = get_Y(X_train, function_type, paras)
    Y_test = get_Y(X_test, function_type, paras)
複製代碼

噪聲是在 0 均值的正態分佈中隨機抽樣獲得的。我設置了噪聲的方差等於 f(X) 的方差,藉此保證咱們數據中的「信號和噪聲」具備可比性,且噪聲不會在信號中有損失,反之亦然。

訓練

注意:在任何模型中都沒有作超參數的調參。 咱們的基本想法是隻在這些模型對所說起的函數上的表現作一個粗略的估計,所以沒有對這些模型作太多的優化。

model_type = 'MLP'

if model_type=='XGBoost':
    model = xgb.XGBRegressor()
elif model_type=='Linear Regression':
    model = LinearRegression()
elif model_type=='SVR':
    model = SVR()
elif model_type=='Decision Tree':
    model = DecisionTreeRegressor()
elif model_type=='Random Forest':
    model = RandomForestRegressor()
elif model_type=='MLP':
    model = MLPRegressor(hidden_layer_sizes=(10, 10))

model.fit(X_train, Y_train)
複製代碼

結果

Results

大多數的表現結果比平均基線要好不少。計算出的平均R方是 70.83%咱們能夠說,機器學習技術對這些簡單的數學函數確實能夠有效地建模

可是經過這個實驗,咱們不只知道了機器學習可否建模這些函數,同時也瞭解了不一樣的機器學習技術在各類基礎函數上的表現是怎樣的。

有些結果是使人驚訝的(至少對我來講),有些則是合理的。總之,這些結果從新認定了咱們的一些先前的想法,也給出了新的想法。

最後,咱們能夠獲得下列結論:

  • 儘管線性迴歸是一個簡單的模型,可是在線性相關的數據上,它的表現是優於其餘模型的
  • 大多數狀況下,決策樹 < 隨機森林 < XGBoost,這是根據實驗的表現獲得的(在以上 6 個結果中有 5 個是顯而易見的)
  • 不像最近實踐中的流行趨勢那樣,XGBoost(6 個結果中只有 2 個表現最好)不該該成爲全部類型的列表數據的一站式解決方案,咱們仍然須要對每一個模型進行公平地比較。
  • 和咱們的猜想相反的是,線性函數不必定是最容易預測的函數。咱們在對數函數上獲得了最好的聚合R方結果,達到了 92.98%
  • 各類技術在不一樣的基礎函數上的效果(相對地)差別十分大,所以,對一個任務選擇何種技術必須通過完善的思考和實驗

完整代碼見個人 github


來點贊,評論和分享吧。建設性的批評和反饋老是受歡迎的!

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索