python數據分析與算法之五 算法


5.1線性回歸算法模型

機器學習

  • 人工智能和機器學習之間的關系

    • 機器學習是實現人工智能的一種技術手段

  • 算法模型

    • 概念:特殊對象。該對象內部封裝了某種還沒有求出解的方程!

    • 作用:

      • 預測:天氣預報

      • 分類:將一個未知分類的事務歸屬到某一種已知的分類中。

    • 算法模型對象內部封裝的方程的解就是算法模型預測或則分類的結果

  • 樣本數據

    • 樣本數據和算法模型之間的關系是什么?

      • 模型的訓練:需要將樣本數據帶入到模型對象中,讓模型對象的方程求出解。

    • 什么是樣本數據?樣本數據是由什么構成的?

      • 特征數據:自變量。往往是有多種特征組成

      • 目標數據:因變量

    • 算法模型的分類:

      • 有監督學習:

        • 如果算法模型對象需要的樣本數據必須有目標數據和特征數據

      • 無監督學習:

        • 如果算法模型對象需要的樣本數據只需要有特征數據即可

    • sklearn模塊中的模型

案例 : Sea distance

  • 城市氣候與海洋的關系研究

    • 1.導入包

      import numpy as np
      import pandas as pd
      from pandas import Series,DataFrame
      
      import matplotlib.pyplot as plt
      from pylab import mpl
      mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默認字體
      mpl.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負號'-'顯示為方塊的問題
      View Code
    • 2.導入數據各個海濱城市數據

      ferrara1 = pd.read_csv('./ferrara_150715.csv')
      ferrara2 = pd.read_csv('./ferrara_250715.csv')
      ferrara3 = pd.read_csv('./ferrara_270615.csv')
      ferrara=pd.concat([ferrara1,ferrara1,ferrara1],ignore_index=True)
      
      torino1 = pd.read_csv('./torino_150715.csv')
      torino2 = pd.read_csv('./torino_250715.csv')
      torino3 = pd.read_csv('./torino_270615.csv')
      torino = pd.concat([torino1,torino2,torino3],ignore_index=True) 
      
      mantova1 = pd.read_csv('./mantova_150715.csv')
      mantova2 = pd.read_csv('./mantova_250715.csv')
      mantova3 = pd.read_csv('./mantova_270615.csv')
      mantova = pd.concat([mantova1,mantova2,mantova3],ignore_index=True) 
      
      milano1 = pd.read_csv('./milano_150715.csv')
      milano2 = pd.read_csv('./milano_250715.csv')
      milano3 = pd.read_csv('./milano_270615.csv')
      milano = pd.concat([milano1,milano2,milano3],ignore_index=True) 
      
      ravenna1 = pd.read_csv('./ravenna_150715.csv')
      ravenna2 = pd.read_csv('./ravenna_250715.csv')
      ravenna3 = pd.read_csv('./ravenna_270615.csv')
      ravenna = pd.concat([ravenna1,ravenna2,ravenna3],ignore_index=True)
      
      asti1 = pd.read_csv('./asti_150715.csv')
      asti2 = pd.read_csv('./asti_250715.csv')
      asti3 = pd.read_csv('./asti_270615.csv')
      asti = pd.concat([asti1,asti2,asti3],ignore_index=True)
      
      bologna1 = pd.read_csv('./bologna_150715.csv')
      bologna2 = pd.read_csv('./bologna_250715.csv')
      bologna3 = pd.read_csv('./bologna_270615.csv')
      bologna = pd.concat([bologna1,bologna2,bologna3],ignore_index=True)
      
      piacenza1 = pd.read_csv('./piacenza_150715.csv')
      piacenza2 = pd.read_csv('./piacenza_250715.csv')
      piacenza3 = pd.read_csv('./piacenza_270615.csv')
      piacenza = pd.concat([piacenza1,piacenza2,piacenza3],ignore_index=True)
      
      cesena1 = pd.read_csv('./cesena_150715.csv')
      cesena2 = pd.read_csv('./cesena_250715.csv')
      cesena3 = pd.read_csv('./cesena_270615.csv')
      cesena = pd.concat([cesena1,cesena2,cesena3],ignore_index=True)
      
      faenza1 = pd.read_csv('./faenza_150715.csv')
      faenza2 = pd.read_csv('./faenza_250715.csv')
      faenza3 = pd.read_csv('./faenza_270615.csv')
      faenza = pd.concat([faenza1,faenza2,faenza3],ignore_index=True)
      View Code
    • 3.去除沒用的列

      city_list = [faenza,cesena,piacenza,bologna,asti,ravenna,milano,mantova,torino,ferrara]
      for city in city_list:
          city.drop(labels='Unnamed: 0',axis=1,inplace=True)
          
      faenza.head()
      View Code

    • 4.顯示最高溫度於離海遠近的關系(觀察多個城市)

      max_temp = []
      dist_list = []
      for city in city_list:
          temp = city['temp'].max()
          max_temp.append(temp)
          dist = city['dist'][0]
          dist_list.append(dist)
      max_temp
      dist_list
      View Code

散點圖的繪制

plt.scatter(dist_list,max_temp)    # plt.scatter(x,y) 
plt.xlabel('距離')
plt.ylabel('最高溫度')
plt.title('最高溫度和距離直接的關系')
View Code

線形圖的繪制

plt.plot(dist_list,max_temp)
plt.xlabel('距離')
plt.ylabel('最高溫度')
plt.title('最高溫度和距離直接的關系')
View Code

  • 需要我們建立一個溫度模型,讓其可以根據一個距離預測吃該距離對應城市的最高溫度是多少

    #線性回歸算法模型 y = wx + b  ==> y = 3x + 5
    from sklearn.linear_model import LinearRegression
    linner = LinearRegression() #算法模型對象
    
    #樣本數據的提取
    feature = np.array(dist_list) #數組形式的特征數據
    target = np.array(max_temp)   #數組形式的目標數據
    feature.shape
    View Code

    #訓練模型
    linner.fit(feature.reshape(-1,1),target) # X表示特征數據必須是二維的!!!
    #基於訓練好的模型對象實現預測功能(獲取方程的解)
    linner.predict([[266],[333]])
    View Code

    x = np.linspace(0,400,num=100)
    y = linner.predict(x.reshape(-1,1))
    
    plt.scatter(dist_list,max_temp)
    plt.scatter(x,y)
    plt.xlabel('距離')
    plt.ylabel('最高溫度')
    plt.title('最高溫度和距離直接的關系')
    View Code

     

5.2KNN算法模型

5.2.1k-近鄰算法原理

  • 簡單地說,K-近鄰算法采用測量不同特征值之間的距離方法進行分類(k-Nearest Neighbor,KNN)

    • 優點:精度高、對異常值不敏感、無數據輸入假定。

    • 缺點:時間復雜度高、空間復雜度高。

      • 1、當樣本不平衡時,比如一個類的樣本容量很大,其他類的樣本容量很小,輸入一個樣本的時候,K個臨近值中大多數都是大樣本容量的那個類,這時可能就會導致分類錯誤。改進方法是對K臨近點進行加權,也就是距離近的點的權值大,距離遠的點權值小。

      • 2、計算量較大,每個待分類的樣本都要計算它到全部點的距離,根據距離排序才能求得K個臨近點,改進方法是:先對已知樣本點進行剪輯,事先去除對分類作用不大的樣本。

    • 適用數據范圍:數值型和標稱型 標稱型:標稱型目標變量的結果只在有限目標集中取值,如真與假(標稱型目標變量主要用於分類) 數值型:數值型目標變量則可以從無限的數值集合中取值,如0.100,42.001等 (數值型目標變量主要用於回歸分析)

工作原理

  • 訓練樣本集

    • 存在一個樣本數據集合,也稱作訓練樣本集,並且樣本集中每個數據都存在標簽,即我們知道樣本集中每一數據 與所屬分類的對應關系。輸人沒有標簽的新數據后,將新數據的每個特征與樣本集中數據對應的 特征進行比較,然后算法提取樣本集中特征最相似數據(最近鄰)的分類標簽。一般來說,我們 只選擇樣本數據集中前K個最相似的數據,這就是K-近鄰算法中K的出處,通常K是不大於20的整數。 最后 ,選擇K個最相似數據中出現次數最多的分類,作為新數據的分類。

  • 電影類別KNN分析

   

  

  • 歐幾里得距離(Euclidean Distance)

  • 計算過程圖

kNN近鄰分類算法的原理

  • 從上圖中我們可以看到,圖中的數據集都有了自己的標簽,一類是藍色的正方形,一類是紅色的三角形,那個綠色的圓形是我們待分類的數據

  • 如果K=3,那么離綠色點最近的有2個紅色三角形和1個藍色的正方形,這3個點投票,於是綠色的這個待分類點屬於紅色的三角形.

  • 如果K=5,那么離綠色點最近的有2個紅色三角形和3個藍色的正方形,這5個點投票,於是綠色的這個待分類點屬於藍色的正方形

  • 我們可以看到,KNN本質是基於一種數據統計的方法!其實很多機器學習算法也是基於數據統計的

  • 總結

    • KNN是一種基於記憶的學習(memory-based learning),也是基於實例的學習(instance-based learning),屬於惰性學習(lazy learning)。即它沒有明顯的前期訓練過程,而是程序開始運行時,把數據集加載到內存后,不需要進行訓練,就可以開始分類了。

5.2.2案例:電影分類

  • 有人曾經統計過很多電影的打斗鏡頭和接吻鏡頭,下圖顯示了6部電影的打斗和接吻次數。假如有一部未看過的電影,如何確定它是愛情片還是動作片呢?我們可以使用K-近鄰算法來解決這個問題。

    首先我們需要知道這個未知電影存在多少個打斗鏡頭和接吻鏡頭,上圖中問號位置是該未知電影出現的鏡頭數圖形化展示,具體數字參見下表。

    即使不知道未知電影屬於哪種類型,我們也可以通過某種方法計算出來。首先計算未知電影與樣本集中其他電影的距離,如圖所示。

現在我們得到了樣本集中所有電影與未知電影的距離,按照距離遞增排序,可以找到K個距 離最近的電影。假定k=3,則三個最靠近的電影依次是California Man、He's Not Really into Dudes、Beautiful Woman。K-近鄰算法按照距離最近的三部電影的類型,決定未知電影的類型,而這三部電影全是愛情片,因此我們判定未知電影是愛情片。

5.2.3在scikit-learn庫中使用k-近鄰算法

import pandas as pd
df = pd.read_excel('../../my_films.xlsx')
df


feature = df[['Action lens','Love lens']]
target = df['target']
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=2)    #導出未知事物周圍三個數據
knn.fit(feature,target)
knn.score(feature,target)    # 給n_neighbors=2 打分


knn.predict([[60,50]])
View Code

用於分類

import sklearn.datasets as datasets   #提供大量基於機械學習樣本數據
datasets.load_iris()
View Code

預測年收入是否大於50K美元

  • 數據的讀取

    df = pd.read_csv('../data/adults.txt')
    df.head(1)
    View Code

  • 獲取年齡、教育程度、職位、每周工作時間作為機器學習數據 ,獲取薪水作為對應結果

    feature = df[['age','education_num','occupation','hours_per_week']]
    target = df['salary']
    occ_arr = feature['occupation'].unique()
    dic = {}
    for i in range(occ_arr.size):
        dic[occ_arr[i]] = i
    feature['occupation'] = feature['occupation'].map(dic)
    feature.head()
    View Code

  • 切片:訓練數據和預測數據 32560

    #訓練數據:負責模型的訓練
    x_train = feature[0:32500]
    y_train = target[0:32500]
    #測試數據:負責測試模型的精准度
    x_test = feature[32500:]
    y_test = target[32500:]
    View Code
  • 實例化模型

    knn = KNeighborsClassifier(n_neighbors=20)
    knn.fit(x_train,y_train)
    knn.score(x_train,y_train)
    View Code

  • 測試精准度

    print('模型的分類結果:',knn.predict(x_test))
    print('真實的分類結果:',y_test)
    View Code
    • 測試

      knn.predict([[45,13,4,50]])
      View Code

5.2.4KNN手寫數字識別

  • 手寫數字是一張圖片,讓knn模型將圖片中的數據識別出來

  • 包的導入

    import numpy as np
    import matplotlib .pyplot as plt 
    from sklearn.neighbors import KNeighborsClassifier
    View Code
  • 圖片的導入

    img_arr = plt.imread('./data/3/3_33.bmp')
    img_arr.shape
    View Code

    plt.imshow(img_arr)
    View Code

  • 提取樣本數據

    feature = []   #樣本數據
    target = []    #目標數據
    for i in range(10):
        for j in range(1,501):   #data/3/3_33.bmp
            imgPath = './data/'+str(i)+'/'+str(i)+'_'+str(j)+'.bmp'
            img_arr = plt.imread(imgPath)
            feature.append(img_arr)
            target.append(i)
    View Code
  • 將列表形式的樣本轉成數組形式的

    feature = np.array(feature)
    target = np.array(target)
    View Code

    

  • 將三維數組變成二維

    feature = feature.reshape((5000,784))
    feature.shape
    View Code

    

  • 對樣本數據進行打亂

    np.random.seed(10)
    np.random.shuffle(feature)
    np.random.seed(10)
    np.random.shuffle(target)
    View Code
  • 拆分訓練數據和測試數據

    x_train = feature[0:4980]
    y_train = target[0:4980]
                     
    x_test = feature[4980:]
    y_test = target[4980:]
    View Code
  • 訓練模型

    knn = KNeighborsClassifier(n_neighbors = 17 )
    knn.fit(x_train,y_train)
    
    print('模型分類的結果:',knn.predict(x_test))
    print('真實是分類結果:',y_test)
    View Code

  • 將訓練好的模型進行保存

    from sklearn.externals import joblib
    joblib.dump(knn,'./knn_1.n')
    View Code
  • 加載保存好的模型

    #加載保存好的模型
    knn = joblib.load('./knn_1.n')
    View Code
  • 讓模型識別外部圖片

    ex_img_arr = plt.imread('./數字.jpg')
    plt.imshow(ex_img_arr)
    View Code

  • 圖片的裁剪

    #將4的區域局部裁剪
    img_4_arr = ex_img_arr[100:160,0:60,:]
    
    img_4_arr
    plt.imshow(img_4_arr)
    View Code
     

  • 降維度

    img_4_arr = img_4_arr.mean(axis=2)
    img_4_arr.shape
    View Code

  • 像素的等比壓縮

    import scipy.ndimage as ndimage
    eight = ndimage.zoom(img_4_arr,zoom=(28/60,28/60))
    plt.imshow(eight)
    View Code

5.3查找算法

5.3.1二分查找

  • 有序列表對於我們的實現搜索是很有用的。在順序查找中,當我們與第一個元素進行比較時,如果第一個元素不是我們要查找的,則最多還有 n-1 個元素需要進行比較。 二分查找則是從中間元素開始,而不是按順序查找列表。 如果該元素是我們正在尋找的元素,我們就完成了查找。 如果它不是,我們可以使用列表的有序性質來消除剩余元素的一半。如果我們正在查找的元素大於中間元素,就可以消除中間元素以及比中間元素小的一半元素。如果該元素在列表中,肯定在大的那半部分。然后我們可以用大的半部分重復該過程,繼續從中間元素開始,將其與我們正在尋找的內容進行比較。

    def sort(alist,item): #item就是我們要找的元素
        low = 0 #進行二分查找操作的列表中第一個元素的下標
        high = len(alist)-1#進行二分查找操作的列表中最后一個元素的下標
        find = False
        
        while low <= high:
            mid = (low+high) // 2 #中間元素的下標
            if item > alist[mid]:#我們要找的數比中間元素值大,則意味着我們要找的數在中間元素的右側
                low = mid + 1
            elif item < alist[mid]:#找的數比中間元素小,則意味着我們要找的數是在中間元素左側
                high = mid - 1
            else:#找到啦
                find = True
                break
        return find
           
    print(sort(alist,51))
    View Code

5.4排序算法

5.4.1冒泡排序

  • 1.將列表中的每兩個列表元素進行大小比較,將兩個元素中較大的數值逐步向后移動

  • 2.

    def sort(alist):
        for j in range(0,len(alist)-1):
            
            for i in range(len(alist)-1-j):
                if alist[i] > alist[i+1]:
                   alist[i],alist[i+1] = alist[i+1],alist[i]
        print(alist)
    alist = [4,11,7,6,8,9]
    sort(alist)
    View Code

5.4.2選擇排序

  • 1.直接將列表中最大值找出,放在列表最后的位置

    def sort(alist):
        max = 0 #max中存儲的是列表中元素值最大數的下標,最開始先假設列表為0的元素為最大值
        for i in range(0,len(alist)-1):
            if alist[max] < alist[i+1]:
                max = i + 1
        #將最大值放在列表末尾的位置
        alist[max],alist[len(alist)-1] = alist[len(alist)-1],alist[max]
        print(alist)
    View Code

  • 2

    def sort(alist):
        for j in range(len(alist)-1,0,-1):   #5,4,3,2,1
            max = 0    #max中存儲的是列表中元素值最大數的下標,最開始先假設列表為0的元素為最大值 
            for i in range(0,j):   #len(alist)-1 ==> j
                if alist[max] < alist[i+1]:
                    max = i + 1
            #將最大值放在列表末尾的位置
            alist[max],alist[j] = alist[j],alist[max]
        print(alist)
    View Code

5.4.3插入排序

  • 插入排序的主要思想是每次取一個列表元素與列表中已經排序好的列表段進行比較,然后插入從而得到新的排序好的列表段,最終獲得排序好的列表。比如,待排序列表為[49,38,65,97,76,13,27,49],則比較的步驟和得到的新列表如下:(帶有背景顏色的列表段是已經排序好的,紅色背景標記的是執行插入並且進行過交換的元素)

    #step_1
    i = 1 #i表示的是列表中左側部分有序部分的數據個數,其次還需要讓i充當列表的下標
    if alist[i] < alist[i-1]:
        alist[i],alist[i-1] = alist[i-1],alist[i]
        i += 1
    #step_2
    i = 2
    #alist[i] :亂序部分的第一個元素
    #alist[i-1] :有序部分的第二個元素
    while i >=1:
        if alist[i] < alist[i-1]:
            alist[i],alist[i-1] = alist[i-1],alist[i]
            i -= 1
        else:
            break
    #step_3
    for i in range(1,len(alist)+1):
        #alist[i] :亂序部分的第一個元素
        #alist[i-1] :有序部分的第二個元素
        while i >=1:
            if alist[i] < alist[i-1]:
                alist[i],alist[i-1] = alist[i-1],alist[i]
                i -= 1
            else:
                break
    #完整版
    def sort(alist):
        for i in range(1,len(alist)):
            #alist[i] :亂序部分的第一個元素
            #alist[i-1] :有序部分的第二個元素
            while i >= 1:
                if alist[i] < alist[i-1]:
                    alist[i],alist[i-1] = alist[i-1],alist[i]
                    i -= 1
                else:
                    break
        print(alist)
    View Code

5.4.4希爾排序

  • 希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序算法的一種更高效的改進版本,

  • 該方法的基本思想是:

    • 先將整個待排元素序列分割成若干個子序列(由相隔某個“增量(gap)”的元素組成的)分別進行直接插入排序,

    • 然后依次縮減增量再進行排序,待整個序列中的元素基本有序(增量足夠小)時,再對全體元素進行一次直接插入排序。因為直接插入排序在元素基本有序的情況下(接近最好情況),效率是很高的,因此希爾排序在時間效率比直接插入排序有較大提高。

    #step_1
    def sort(alist):
        gap = len(alist) // 2
        #將插入排序當做增量為1的希爾排序
        for i range(1,len(alist)):
            while i > 0 :
                if alist[i] < alist[i-1]:
                    alist[i],alist[i-1] = alist[i-1],alist[i]
                    i -= 1
                else:
                    break
    ##step_2
    def sort(alist):
        gap = len(alist) // 2
        #將增量設置成gap
        for i range(gap,len(alist)):
            while i > 0 :
                if alist[i] < alist[i-gap]:
                    alist[i],alist[i-gap] = alist[i-gap],alist[i]
                    i -= gap
                else:
                    break
    #完整版
    #繼續縮小增量
    def sort(alist):
        gap = len(alist) // 2
        while gap >= 1:
            #將增量設置成gap
            for i in range(gap,len(alist)):
                while i > 0 :
                    if alist[i] < alist[i-gap]:
                        alist[i],alist[i-gap] = alist[i-gap],alist[i]
                        i -= gap
                    else:
                        break
            gap //= 2
        return alist
    View Code

5.4.5快速排序

  • 將列表中第一個元素設定為基准數字,賦值給mid變量,然后將整個列表中比基准小的數值放在基准的左側,比基准到的數字放在基准右側。然后將基准數字左右兩側的序列在根據此方法進行排放。

  • 定義兩個指針,low指向最左側,high指向最右側

  • 然后對最右側指針進行向左移動,移動法則是,如果指針指向的數值比基准小,則將指針指向的數字移動到基准數字原始的位置,否則繼續移動指針。

  • 如果最右側指針指向的數值移動到基准位置時,開始移動最左側指針,將其向右移動,如果該指針指向的數值大於基准則將該數值移動到最右側指針指向的位置,然后停止移動。

  • 如果左右側指針重復則,將基准放入左右指針重復的位置,則基准左側為比其小的數值,右側為比其大的數值。

    #第一次排序:將將比基准小的排列在基准左側,def sort(alist):
    def sort(alist):
        low = 0
        high = len(alist)-1
        #基准:最左側的數值
        mid = alist[low]
        #low和high的關系只能是小於,當等於的時候就要填充mid了
        while low < high:
            while low < high:
                if alist[high] > mid:
                    high -= 1
                else:
                    alist[low] = alist[high]
                    break
            while low < high:
                if alist[low] < mid:
                    low += 1
                else:
                    alist[high] = alist[low]
                    break
            
            #當low和high重復的時候,將mid填充
            if low == high:
                alist[low] = mid #or alist[high] = mid  
                break
        return alist
    #完整版
    def sort(alist,start,end):
        low = start
        high = end
        #遞歸結束的條件
        if low > high:
            return
        #基准:最左側的數值
        mid = alist[low]
        #low和high的關系只能是小於,當等於的時候就要填充mid了
        while low < high:
            while low < high:
                if alist[high] > mid:
                    high -= 1
                else:
                    alist[low] = alist[high]
                    break
            while low < high:
                if alist[low] < mid:
                    low += 1
                else:
                    alist[high] = alist[low]
                    break
            
            #當low和high重復的時候,將mid填充
            if low == high:
                alist[low] = mid #or alist[high] = mid  
                break
        #執行左側序列
        sort(alist,start,high-1)
        #執行右側序列
        sort(alist,low+1,end)
        
        return alist
    View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM