1. 程式人生 > >機器學習折騰記(1):先成功執行一個Python例子

機器學習折騰記(1):先成功執行一個Python例子

最近,聽很多朋友都在說人工智慧越來越火,想要了解其中究竟,於是我就推薦了幾本書,但結果卻是,除了工程師朋友能夠勉強看下去外,其餘大部分人到最後都不得放棄了,原因是太多數學公式,太難理解了。

比如,《深度學習》這本書,算得上一本科普書了,是專門寫給一般人看的,其中也包含了大量的數學和公式。

我倒是認為,並不是因為看不懂,而是其中的數學很容激發大部分一般人的學校噩夢,想到好不容易畢業上班不用看數學了,結果又被喚起,自然讀不下去。

可數學是學習機器學習繞不開的一道關卡,必然要去解決,搞技術的人多多少少也要接觸數學,可還是很多人不想看數學。

不過,以我的經驗來看,不是沒有辦法,但要換個思路來切入,就是從學習python開始,上一篇文章

《機器學習折騰記0:開啟從Scikit-Learn入門機器學習演算法之旅》,我介紹了機器學習python環境的安裝,提到了《機器學習系統設計》這本書,並不是因為這本書好理解,而是因為他沒有像很多常規的機器學習書或文章那樣,一上來就介紹很多基礎知識,把人搞暈,而是提供了一個另類的不錯的切入思路,我們就從這本書開始。

提個好問題

作者說,機器學習 (ML)就是教機器自己來完成任務。這和我們以為的機器是不是應該具備了生物智慧是不同的。

換句話說,機器學習就是一種計算機能夠執行的演算法,讓機器能夠模仿人類一樣學習知識。

既然是演算法,作者一開始還提出了幾個很好的問題:在無數的演算法中應該選擇哪一個呢?所有的設定都正確嗎?你得到最優的結果了嗎?怎麼知道有沒有更好的演算法?或者,你的資料是否就是“正確的”?

資料就是機器學習的養料,如果你認識做資料探勘或資料分析的人,他們一定能夠清晰的給你解釋什麼是機器學習,以及人工智慧的本質到底是什麼。

所以提一個好問題很重要!

核心三步法

多說一句,這本書本身就是一本是實戰書,每個小結都是一個操作步驟,你可以按部就班的看。

不過,如果你不動手去敲程式碼,只是想用隨書的程式碼的話,那很遺憾,很多時候都執行不了,可能是新版本不相容老版本,或者各種環境編譯的問題,總之,我們的目標是學到有用的東西,而不是看上去好像懂了。

對於機器學習的流程來說,就是簡單的三步法——

1、讀取資料
2、預處理和清洗資料
3、選擇正確的模型和學習演算法

很多時候,我們都把問題搞複雜了,特別是對於計算機相關書籍,常常都容易陷入實現細節中去,這也是為什麼很多人看著看著就昏了的原因,因為一開始沒有抓住最重要的核心脈絡,要是再加上數學公式,就更難看下去了。

我的建議是,先放下里面難懂的數學解釋,包括每一節的說明,先執行起來一個程式,從感性上去感受一下,機器學習在執行中是什麼樣子,就夠了。

我曾經及時一直抓住要解決實際問題這條主線而出發去學習理解演算法時,效率是非常高的,而如果從所謂的基礎學起,可能早都放棄了,先來看一下最終效果圖。

【過擬合的例子,你看懂了嗎?】

回答最初的問題

得到上面的圖是需要經過一番折騰的,我之所以省略了抄書的步驟,是因為實戰就是要你去動手敲程式碼,也是檢驗你python基礎的時候了,我們最終就會得到了一個模型,我們認為它可以最好地代表資料生成過程。

而這個模型就是機器學習的最終結果,而我們拿著這個模型就可以預測未來的資料走向發展,但可惜的時,現實中有一種叫做突變的因素存在。

還是那幾個問題:在無數的演算法中應該選擇哪一個呢?所有的設定都正確嗎?你得到最優的結果了嗎?怎麼知道有沒有更好的演算法?或者,你的資料是否就是“正確的”?

如果你依然有興趣看下去,那就一直不要忘記這幾個問題,以及你為什麼而開始去學習機器學習。

實現程式碼

如果你認真按照前一篇文章《機器學習折騰記0:開啟從Scikit-Learn入門機器學習演算法之旅》的步驟做了,下面的程式碼是一定能執行的,裡面有很多註釋程式碼,在看書時也可以一段一段的跟著試試。

#!/usr/bin/env python
# _*_ coding:utf-8 _*_

import scipy as sp
import matplotlib.pyplot as plt

# 畫圖的一些顏色和線條形狀
colors = ['g', 'k', 'b', 'm', 'r']
linestyles = ['-', '-.', '--', ':', '-']
# 定義一個畫圖的類
def plot_models(x, y, models, fname=None, mx=None, ymax=None, xmin=None):
    plt.clf()
    plt.scatter(x, y, s=10)
    plt.title("Web traffic over the last month")
    plt.xlabel("Time")
    plt.ylabel("Hits/hour")
    plt.xticks(
        [w * 7 * 24 for w in range(10)], ['week %i' % w for w in range(10)])

    if models:
        if mx is None:
            mx = sp.linspace(0, x[-1], 1000)
        for model, style, color in zip(models, linestyles, colors):
            # print "Model:",model
            # print "Coeffs:",model.coeffs
            plt.plot(mx, model(mx), linestyle=style, linewidth=2, c=color)

        plt.legend(["d=%i" % m.order for m in models], loc="upper left")

    plt.autoscale(tight=True)
    plt.ylim(ymin=0)
    if ymax:
        plt.ylim(ymax=ymax)
    if xmin:
        plt.xlim(xmin=xmin)
    plt.grid(True, linestyle='-', color='0.75')
    # plt.show() # 這個是會阻塞的,看最後一個,就在程式碼最後加
    # plt.savefig(fname)
def error(f, x, y):
    return sp.sum((f(x)-y)**2)




data = sp.genfromtxt("web_traffic.tsv", delimiter="\t")
print(data[:10]) #列印前10個數據
print(data.shape)

# 預處理和清洗資料
x = data[:,0] #對應第1列
y = data[:,1] #對應第2列

isnan_num = sp.sum(sp.isnan(y))
print(isnan_num)

x = x[~sp.isnan(y)]  #這裡是取反操作,y值為空則不取
y = y[~sp.isnan(y)]

# import matplotlib.pyplot as plt
# plt.scatter(x,y)
# plt.title("Web traffic over the last month")
# plt.xlabel("Time")
# plt.ylabel("Hits/hour")
# plt.xticks([w*7*24 for w in range(10)],['week %i'%w for w in range(10)])
# plt.autoscale(tight=True)
# plt.grid()
# plt.show()

fp1, residuals, rank, sv, rcond = sp.polyfit(x, y, 1, full=True)

print("Model parameters: %s" % fp1)
# print(res)
#f(x) = 2.59619213 * x + 989.02487106

f1 = sp.poly1d(fp1)
print(error(f1, x, y))

fx = sp.linspace(0,x[-1], 1000) # 生成X值用來作圖
# plt.plot(fx, f1(fx), linewidth=4,color='green')
# plt.legend(["d=%i" % f1.order], loc="upper left")
# plt.grid()
# plt.show() #
plot_models(x, y, None)

# d=2
f2p = sp.polyfit(x, y, 2)
print(f2p)
f2 = sp.poly1d(f2p)
print(error(f2, x, y))
# plt.plot(fx, f2(fx), linewidth=3, color='red')
# plt.legend(["d=%i" % f2.order], loc="upper left")

#d=3
f3p = sp.polyfit(x, y, 3)
print(f3p)
f3 = sp.poly1d(f3p)
print(error(f3, x, y))
# plt.plot(fx, f3(fx), linewidth=3, color='black')
# plt.legend(["d=%i" % f3.order], loc="upper left")

#d=10
f10p = sp.polyfit(x, y, 10)
print(f10p)
f10 = sp.poly1d(f10p)
print(error(f10, x, y))
# plt.plot(fx, f10(fx), linewidth=3, color='gray')
# plt.legend(["d=%i" % f10.order], loc="upper left")

#d=100
f100p = sp.polyfit(x, y, 100)
print(f100p)
f100 = sp.poly1d(f100p)
print(error(f100, x, y))
# plt.plot(fx, f100(fx), linewidth=3, color='yellow')
# plt.legend(["d=%i" % f100.order], loc="upper left")

plot_models(
    x, y, [f1, f2, f3, f10, f100])

inflection = 3*7*24 # 計算拐點的小時數,書中3.5要報錯,改為3
xa = x[:inflection] # 拐點之前的資料
ya = y[:inflection]
xb = x[inflection:] # 之後的資料
yb = y[inflection:]
fa = sp.poly1d(sp.polyfit(xa, ya, 1))
fb = sp.poly1d(sp.polyfit(xb, yb, 1))
fa_error = error(fa, xa, ya)
fb_error = error(fb, xb, yb)
# print("Error inflection=%f" % (fa + fb_error))

# plot_models(x, y, [fa, fb])

# plt.plot(fx, fa(fx), linewidth=3, color='c')
# plt.legend(["d=%i" % fa.order], loc="upper left")
# plt.plot(fx, fb(fx), linewidth=3, color='c')
# plt.legend(["d=%i" % fb.order], loc="upper left")

plot_models(x, y, [f1, f2, f3, f10, f100], None,
    mx=sp.linspace(0 * 7 * 24, 6 * 7 * 24, 100),
    ymax=10000, xmin=0 * 7 * 24)

frac = 0.3
split_idx = int(frac * len(xb))
shuffled = sp.random.permutation(list(range(len(xb))))
test = sorted(shuffled[:split_idx])
train = sorted(shuffled[split_idx:])
fbt1 = sp.poly1d(sp.polyfit(xb[train], yb[train], 1))
fbt2 = sp.poly1d(sp.polyfit(xb[train], yb[train], 2))
fbt3 = sp.poly1d(sp.polyfit(xb[train], yb[train], 3))
fbt10 = sp.poly1d(sp.polyfit(xb[train], yb[train], 10))
fbt100 = sp.poly1d(sp.polyfit(xb[train], yb[train], 100))

plot_models(
    x, y, [fbt1, fbt2, fbt3, fbt10, fbt100], None,
    mx=sp.linspace(0 * 7 * 24, 6 * 7 * 24, 100),
    ymax=10000, xmin=0 * 7 * 24)

from scipy.optimize import fsolve
print(fbt2)
print(fbt2 - 100000)
reached_max = fsolve(fbt2 - 100000, 800) / (7 * 24)
print("100,000 hits/hour expected at week %f" % reached_max[0])


plt.show() # 只看最後一個時開啟

小結

你可能也發現了,不管是使用現成的機器學習庫,還是自己重複造輪子實現演算法,最終花更多精力的是在資料上,更重要的是理解資料和提煉資料。

換句話說,最重要的是的對資料的分析,就像我們學習知識一樣,理解知識,提煉知識才是更重要的。

而我們要學習的就是不同的演算法在對資料的處理,以及如何優化這些演算法,同時還要結合自己的應用場景來具體分析,不要讓“更多看上去很厲害的演算法”分散了你的注意力。

參考資源

1、《機器學習系統設計》
2、《Python語言指南》