Python機器學習筆記:sklearn庫的學習


  網上有很多關於sklearn的學習教程,大部分都是簡單的講清楚某一方面,所以最好的教程其實就是官方文檔。

  官方文檔地址:https://scikit-learn.org/stable/

(可是官方文檔非常詳細,同時許多人對官方文檔的理解和結構上都不能很好地把握,我也打算好好學習sklearn,這可能是機器學習的神器),下面先簡單介紹一下sklearn。

  自2007年發布以來,scikit-learn已經成為Python重要的機器學習庫了,scikit-learn簡稱sklearn,支持包括分類,回歸,降維和聚類四大機器學習算法。還包括了特征提取,數據處理和模型評估者三大模塊。

  sklearn是Scipy的擴展,建立在Numpy和matplolib庫的基礎上。利用這幾大模塊的優勢,可以大大的提高機器學習的效率。

  sklearn擁有着完善的文檔,上手容易,具有着豐富的API,在學術界頗受歡迎。sklearn已經封裝了大量的機器學習算法,包括LIBSVM和LIBINEAR。同時sklearn內置了大量數據集,節省了獲取和整理數據集的時間。

一,sklearn官方文檔的內容和結構

1.1 sklearn官方文檔的內容

  定義:針對經驗E和一系列的任務T和一定表現的衡量P,如果隨着經驗E的積累,針對定義好的任務T可以提高表現P,就說明機器具有學習能力。

1.2 sklearn官方文檔結構

  由圖中,可以看到庫的算法主要有四類:分類,回歸,聚類,降維。其中:

  • 常用的回歸:線性、決策樹、SVM、KNN ;集成回歸:隨機森林、Adaboost、GradientBoosting、Bagging、ExtraTrees
  • 常用的分類:線性、決策樹、SVM、KNN,朴素貝葉斯;集成分類:隨機森林、Adaboost、GradientBoosting、Bagging、ExtraTrees
  • 常用聚類:k均值(K-means)、層次聚類(Hierarchical clustering)、DBSCAN
  • 常用降維:LinearDiscriminantAnalysis、PCA

  這個流程圖代表:藍色圓圈是判斷條件,綠色方框是可以選擇的算法,我們可以根據自己的數據特征和任務目標去找一條自己的操作路線。

  sklearn中包含眾多數據預處理和特征工程相關的模塊,雖然剛接觸sklearn時,大家都會為其中包含的各種算法的廣度深度所震驚,但其實sklearn六大板塊中有兩塊都是關於數據預處理和特征工程的,兩個板塊互相交互,為建模之前的全部工程打下基礎。

  • 模塊preprocessing:幾乎包含數據預處理的所有內容
  • 模塊Impute:填補缺失值專用
  • 模塊feature_selection:包含特征選擇的各種方法的實踐
  • 模塊decomposition:包含降維算法

 二,sklearn的快速使用

  傳統的機器學習任務從開始到建模的一般流程就是:獲取數據——》數據預處理——》訓練模型——》模型評估——》預測,分類。本次我們將根據傳統機器學習的流程,看看在每一步流程中都有哪些常用的函數以及他們的用法是怎么樣的。那么首先先看一個簡單的例子:

  鳶尾花識別是一個經典的機器學習分類問題,它的數據樣本中包括了4個特征變量,1個類別變量,樣本總數為150。

  它的目標是為了根據花萼長度(sepal length)、花萼寬度(sepal width)、花瓣長度(petal length)、花瓣寬度(petal width)這四個特征來識別出鳶尾花屬於山鳶尾(iris-setosa)、變色鳶尾(iris-versicolor)和維吉尼亞鳶尾(iris-virginica)中的哪一種。

# 引入數據集,sklearn包含眾多數據集
from sklearn import datasets
# 將數據分為測試集和訓練集
from sklearn.model_selection import train_test_split
# 利用鄰近點方式訓練數據
from sklearn.neighbors import KNeighborsClassifier

# 引入數據,本次導入鳶尾花數據,iris數據包含4個特征變量
iris = datasets.load_iris()
# 特征變量
iris_X = iris.data
# print(iris_X)
print('特征變量的長度',len(iris_X))
# 目標值
iris_y = iris.target
print('鳶尾花的目標值',iris_y)
# 利用train_test_split進行訓練集和測試機進行分開,test_size占30%
X_train,X_test,y_train,y_test=train_test_split(iris_X,iris_y,test_size=0.3)
# 我們看到訓練數據的特征值分為3類
# print(y_train)
'''
[1 1 0 2 0 0 0 2 2 2 1 0 2 0 2 1 0 1 0 2 0 1 0 0 2 1 2 0 0 1 0 0 1 0 0 0 0
 2 2 2 1 1 1 2 0 2 0 1 1 1 1 2 2 1 2 2 2 0 2 2 2 0 1 0 1 0 0 1 2 2 2 1 1 1
 2 0 0 1 0 2 1 2 0 1 2 2 2 1 2 1 0 0 1 0 0 1 1 1 0 2 1 1 0 2 2]
 '''
# 訓練數據
# 引入訓練方法
knn = KNeighborsClassifier()
# 進行填充測試數據進行訓練
knn.fit(X_train,y_train)

params = knn.get_params()
print(params)
'''
{'algorithm': 'auto', 'leaf_size': 30, 'metric': 'minkowski',
 'metric_params': None, 'n_jobs': None, 'n_neighbors': 5, 
 'p': 2, 'weights': 'uniform'}

'''

score = knn.score(X_test,y_test)
print("預測得分為:%s"%score)
'''
預測得分為:0.9555555555555556
[1 2 1 1 2 2 1 0 0 0 0 1 2 0 1 0 2 0 0 0 2 2 0 2 2 2 2 1 2 2 2 1 2 2 1 2 0
 2 1 2 1 1 0 2 1]
[1 2 1 1 2 2 1 0 0 0 0 1 2 0 1 0 2 0 0 0 1 2 0 2 2 2 2 1 1 2 2 1 2 2 1 2 0
 2 1 2 1 1 0 2 1]
'''

# 預測數據,預測特征值
print(knn.predict(X_test))
'''
[0 2 2 2 2 0 0 0 0 2 2 0 2 0 2 1 2 0 2 1 0 2 1 0 1 2 2 0 2 1 0 2 1 1 2 0 2
 1 2 0 2 1 0 1 2]
'''
# 打印真實特征值
print(y_test)
'''
[1 2 2 2 2 1 1 1 1 2 1 1 1 1 2 1 1 0 2 1 1 1 0 2 0 2 0 0 2 0 2 0 2 0 2 2 0
 2 2 0 1 0 2 0 0]

'''

  

  下面,我們開始一步步介紹

1,獲取數據

1.1 導入sklearn數據集

  sklearn中包含了大量的優質的數據集,在我們學習機器學習的過程中,我們可以使用這些數據集實現出不同的模型,從而提高我們的動手實踐能力,同時這個過程也可以加深對理論知識的理解和把握。除了引入數據之外,我們還可以通過load_sample_images()來引入圖片。

  首先,要使用sklearn中的數據集,必須導入datasets模塊。

from sklearn import datasets

  下面兩個圖中包含了大部分sklearn中的數據集,調用方式也圖中給出,

   這里我們使用iris的數據來舉個例子,表示導出數據集:

iris = datasets.load_iris() # 導入數據集
X = iris.data # 獲得其特征向量
y = iris.target # 獲得樣本label

   注意,在0.18版本后,新增了一個功能:return_X_y=False

  這個參數什么意思呢?就是控制輸出數據的結構,若選為TRUE,則將因變量和自變量獨立導出,我們看例子:

from sklearn.datasets import load_iris


X, y = load_iris(return_X_y=True)
print(X.shape, y.shape, type(X))
data = load_iris(return_X_y=False)
print(type(data))
# (150, 4) (150,) <class 'numpy.ndarray'>
# <class 'sklearn.utils.Bunch'>

   簡單來說,return_X_y 為TRUE,就是更方便了。

1.1.1  手寫數字數據集

  手寫數字數據集包含1797個0-9的手寫數字數據,每個數據由8 * 8 大小的矩陣構成,矩陣中值的范圍是0-16,代表顏色的深度。

  使用sklearn.datasets.load_digits即可加載相關數據集。

from sklearn.datasets import load_digits
digits = load_digits()
print(digits.data.shape)
print(digits.target.shape)
print(digits.images.shape)
'''
(1797, 64)
(1797,)
(1797, 8, 8)
'''

  展示如下:

import matplotlib.pyplot as plt
from sklearn.datasets import load_digits

digits = load_digits()

plt.matshow(digits.images[0])
plt.show()

 

 

1.2 創建數據集

  我們除了可以使用sklearn自帶的數據集,還可以自己去創建訓練樣本,

具體用法可以參考: https://scikit-learn.org/stable/datasets/

 

  下面我們拿分類問題的樣本生成器舉例子:

from sklearn.datasets.samples_generator import make_classification

X, y = make_classification(n_samples=6, n_features=5, n_informative=2, 
    n_redundant=2, n_classes=2, n_clusters_per_class=2, scale=1.0, 
    random_state=20)

# n_samples:指定樣本數
# n_features:指定特征數
# n_classes:指定幾分類
# random_state:隨機種子,使得隨機狀可重

  測試如下:

>>> for x_,y_ in zip(X,y):
    print(y_,end=': ')
    print(x_)

    
0: [-0.6600737  -0.0558978   0.82286793  1.1003977  -0.93493796]
1: [ 0.4113583   0.06249216 -0.90760075 -1.41296696  2.059838  ]
1: [ 1.52452016 -0.01867812  0.20900899  1.34422289 -1.61299022]
0: [-1.25725859  0.02347952 -0.28764782 -1.32091378 -0.88549315]
0: [-3.28323172  0.03899168 -0.43251277 -2.86249859 -1.10457948]
1: [ 1.68841011  0.06754955 -1.02805579 -0.83132182  0.93286635]

 

1.2.1  用sklearn.datasets.make_blobs來生成數據

  scikit中的make_blobs方法常被用來生成聚類算法的測試數據,直觀地說,make_blobs會根據用戶指定的特征數量,中心點數量,范圍等來生成幾類數據,這些數據可用於測試聚類算法的效果。

sklearn.datasets.make_blobs(n_samples=100, n_features=2, centers=3, 
cluster_std=1.0, center_box=(-10.0, 10.0), shuffle=True,
 random_state=None)[source]

  輸入:

  • n_samples表示產生多少個數據
  • n_features表示數據是幾維
  • centers表示數據點中心,可以輸入int數字,代表有多少個中心,也可以輸入幾個坐標(fixed center locations)
  • cluster_std表示分布的標准差

  返回值:

  • X,[n_samples, n_features]形狀的數組,代表產生的樣本
  • y,[n_samples]形狀的數組,代表每個點的標簽(類別)

 例子(生成三類數據用於聚類(100個樣本,每個樣本2個特征)):

from sklearn.datasets import make_blobs
from matplotlib import pyplot

data,label = make_blobs(n_samples=100,n_features=2,centers=5)

# 繪制樣本顯示
pyplot.scatter(data[:,0],data[:,1],c=label)
pyplot.show()

  結果:

   為每個類別設置不同的方差,只需要在上述代碼中加入cluster_std參數即可:

import matplotlib.pylab as plt
from sklearn.datasets import make_blobs

# 每個樣本有幾個屬性或者特征
n_features = 2

data,target = make_blobs(n_samples=100,n_features=2,centers=3,cluster_std=[1.0,2.0,3.0])
# 在2D圖中繪制樣本,每個樣本顏色不同
plt.scatter(data[:,0],data[:,1],c=target)
plt.show()

  

 

1.2.2  用sklearn.datasets.make_classification來生成數據

  通常用於分類算法

sklearn.datasets.make_classification(n_samples=100, n_features=20, 
n_informative=2, n_redundant=2,n_repeated=0, n_classes=2, 
n_clusters_per_class=2, weights=None,flip_y=0.01, class_sep=1.0,
 hypercube=True,shift=0.0, scale=1.0, shuffle=True, random_state=None)

 輸入: 

  1. n_features :特征個數= n_informative() + n_redundant + n_repeated
  2. n_informative:多信息特征的個數
  3. n_redundant:冗余信息,informative特征的隨機線性組合
  4. n_repeated :重復信息,隨機提取n_informative和n_redundant 特征
  5. n_classes:分類類別
  6. n_clusters_per_class :某一個類別是由幾個cluster構成的

 

1.2.3  用sklearn.datasets.make_gaussian和make_hastie_10_2來生成數據

sklearn.datasets.make_gaussian_quantiles(mean=None, cov=1.0, n_samples=100,
 n_features=2, n_classes=3,shuffle=True, random_state=None)

  利用高斯分位點區分不同數據

sklearn.datasets.make_hastie_10_2(n_samples=12000, random_state=None)

  利用Hastie算法,生成二分類數據

import matplotlib.pyplot as plt
 
from sklearn.datasets import make_classification
from sklearn.datasets import make_blobs
from sklearn.datasets import make_gaussian_quantiles
from sklearn.datasets import make_hastie_10_2
 
plt.figure(figsize=(8, 8))
plt.subplots_adjust(bottom=.05, top=.9, left=.05, right=.95)
 
plt.subplot(421)
plt.title("One informative feature, one cluster per class", fontsize='small')
X1, Y1 = make_classification(n_samples=1000,n_features=2, n_redundant=0, n_informative=1,
                             n_clusters_per_class=1)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(422)
plt.title("Two informative features, one cluster per class", fontsize='small')
X1, Y1 = make_classification(n_samples=1000,n_features=2, n_redundant=0, n_informative=2,
                             n_clusters_per_class=1)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(423)
plt.title("Two informative features, two clusters per class", fontsize='small')
X2, Y2 = make_classification(n_samples=1000,n_features=2, n_redundant=0, n_informative=2)
plt.scatter(X2[:, 0], X2[:, 1], marker='o', c=Y2)
 
 
plt.subplot(424)
plt.title("Multi-class, two informative features, one cluster",
          fontsize='small')
X1, Y1 = make_classification(n_samples=1000,n_features=2, n_redundant=0, n_informative=2,
                             n_clusters_per_class=1, n_classes=3)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(425)
plt.title("Three blobs", fontsize='small')
X1, Y1 = make_blobs(n_samples=1000,n_features=2, centers=3)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(426)
plt.title("Gaussian divided into four quantiles", fontsize='small')
X1, Y1 = make_gaussian_quantiles(n_samples=1000,n_features=2, n_classes=4)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
 
plt.subplot(427)
plt.title("hastie data ", fontsize='small')
X1, Y1 = make_hastie_10_2(n_samples=1000)
plt.scatter(X1[:, 0], X1[:, 1], marker='o', c=Y1)
plt.show()

  結果:

1.2.4  用sklearn.datasets.make_circles和make_moons來生成數據

   生成環線數據

sklearn.datasets.make_circles(n_samples=100, shuffle=True, noise=None, 
random_state=None, factor=0.8)

  factor:外環和內環的尺度因子<1

sklearn.datasets.make_moons(n_samples=100, shuffle=True, noise=None, 
random_state=None)

  生成半環圖

from sklearn.datasets import make_circles
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
import numpy as np
 
fig=plt.figure(1)
x1,y1=make_circles(n_samples=1000,factor=0.5,noise=0.1)
plt.subplot(121)
plt.title('make_circles function example')
plt.scatter(x1[:,0],x1[:,1],marker='o',c=y1)
 
plt.subplot(122)
x1,y1=make_moons(n_samples=1000,noise=0.1)
plt.title('make_moons function example')
plt.scatter(x1[:,0],x1[:,1],marker='o',c=y1)
plt.show()

  結果:

 

2,數據預處理

   數據預處理階段是機器學習中不可缺少的一環,它會使得數據更加有效的被模型或者評估器識別。下面我們來看一下sklearn中有哪些平時我們常用的函數:

from sklearn import preprocessing

  為了使得訓練數據的標准化規則與測試數據的標准化規則同步,preprocessing中提供了很多的Scaler:

  • StandardScaler
  • MaxAbsScaler
  • MinMaxScaler
  • RobustScaler
  • Normalizer
  • 等其他預處理操作

  對應的有直接的函數使用:scale(),maxabs_scale(),minmax_scale(),robust_scale(),normaizer()

sklearn.preprocessing.scale(X)

 

2.1 數據標准化

  標准化:在機器學習中,我們可能要處理不同種類的資料,例如,音訊和圖片上的像素值,這些資料可能是高緯度的,資料標准化后會使得每個特征中的數值平均變為0(將每個特征的值都減掉原始資料中該特征的平均),標准差變為1,這個方法被廣泛的使用在許多機器學習算法中(例如:支持向量機,邏輯回歸和類神經網絡)。

  StandardScaler計算訓練集的平均值和標准差,以便測試數據及使用相同的變換。

  變換后各維特征有0均值,單位方差,也叫z-score規范化(零均值規范化),計算方式是將特征值減去均值,除以標准差。

fit

  用於計算訓練數據的均值和方差,后面就會用均值和方差來轉換訓練數據

fit_transform

  不僅計算訓練數據的均值和方差,還會基於計算出來的均值和方差來轉換訓練數據,從而把數據轉化成標准的正態分布。

transform

  很顯然,它只是進行轉換,只是把訓練數據轉換成標准的正態分布。(一般會把train和test集放在一起做標准化,或者在train集上做標准化后,用同樣的標准化器去標准化test集,此時可以使用scaler)。

data = [[0, 0], [0, 0], [1, 1], [1, 1]]
# 1. 基於mean和std的標准化
scaler = preprocessing.StandardScaler().fit(train_data)
scaler.transform(train_data)
scaler.transform(test_data)

 

  一般來說先使用fit:

scaler = preocessing.StandardScaler().fit(X)

  這一步可以計算得到scaler,scaler里面存的有計算出來的均值和方差。

  再使用transform

scaler.transform(X)

  這一步再用scaler中的均值和方差來轉換X,使X標准化。

  最后,在預測的時候,也要對數據做同樣的標准化處理,即也要用上面的scaler中的均值和方差來對預測時候的特征進行標准化。

  注意:測試數據和預測數據的標准化的方式要和訓練數據標准化的方式一樣,必須使用同一個scaler來進行transform

2.2 最小-最大規范化

  最小最大規范化對原始數據進行線性變換,變換到[0,1]區間(也可以是其他固定最小最大值的區間)。

# 2. 將每個特征值歸一化到一個固定范圍
scaler = preprocessing.MinMaxScaler(feature_range=(0, 1)).fit(train_data)
scaler.transform(train_data)
scaler.transform(test_data)
#feature_range: 定義歸一化范圍,注用()括起來

  

2.3 正則化(normalize)

   當你想要計算兩個樣本的相似度時必不可少的一個操作,就是正則化。其思想是:首先求出樣本的p范數,然后該樣本的所有元素都要除以該范數,這樣最終使得每個樣本的范數都是1。規范化(Normalization)是將不同變化范圍的值映射到相同的固定范圍,常見的是[0,1],也成為歸一化。

  如下例子,將每個樣本變換成unit norm。

>>> X = [[ 1., -1.,  2.],
...      [ 2.,  0.,  0.],
...      [ 0.,  1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')

>>> X_normalized                                      
array([[ 0.40..., -0.40...,  0.81...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 0.  ...,  0.70..., -0.70...]])

  我們可以發現對於每一個樣本都有0.4^2+0.4^2+0.81^2=1。這就是L2 norm,變換后每個樣本的各維特征的平方和為1.類似的,L1 norm則是變換后每個樣本的各維特征的絕對值之和為1.還有max norm,則是將每個樣本的各維特征除以該樣本各維特征的最大值,

  在度量樣本之間相似性時,如果使用的是二次型kernel,則需要做Normalization。

 

2.4 one-hot編碼

  one-hot編碼是一種對離散特征值的編碼方式,在LR模型中常用到,用於給線性模型增加非線性能力。

data = [[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]]
encoder = preprocessing.OneHotEncoder().fit(data)
enc.transform(data).toarray()

  

2.5 特征二值化(Binarization)

  給定閾值,將特征轉換為0/1.

binarizer = sklearn.preprocessing.Binarizer(threshold=1.1)

binarizer.transform(X)

  

2.6 類別特征編碼

  有時候特征時類別型的,而一些算法的輸入必須是數值型,此時需要對其編碼,

enc = preprocessing.OneHotEncoder()
enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
enc.transform([[0, 1, 3]]).toarray()  #array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])

  上面這個例子,第一維特征有兩種值0和1,用兩位去編碼。第二維用三位,第三維用四位。

2.7 標簽編碼(Label encoding)

le = sklearn.preprocessing.LabelEncoder()  
le.fit([1, 2, 2, 6]) 
le.transform([1, 1, 2, 6])  #array([0, 0, 1, 2]) 
#非數值型轉化為數值型
le.fit(["paris", "paris", "tokyo", "amsterdam"])
le.transform(["tokyo", "tokyo", "paris"])  #array([2, 2, 1])

  

3,數據集拆分

  在得到訓練數據集時,通常我們經常會把訓練數據進一步拆分成訓練集和驗證集,這樣有助於我們模型參數的選取。

  train_test_split是交叉驗證中常用的函數,功能是從樣本中隨機的按比例選取train datatestdata,形式為:

X_train,X_test, y_train, y_test =

cross_validation.train_test_split(train_data,train_target,test_size=0.4, random_state=0)

  注意:train_test_split 不再 cross_validation中,已經移到 model_selection 中。

參數解釋

  • train_data:所要划分的樣本特征集
  • train_target:所要划分的樣本結果
  • test_size:樣本占比,如果是整數的話就是樣本的數量
  • random_state:是隨機數的種子。
  • 隨機數種子:其實就是該組隨機數的編號,在需要重復試驗的時候,保證得到一組一樣的隨機數。比如你每次都填1其他參數一樣的情況下你得到的隨機數組是一樣的。但填0或不填,每次都會不一樣。
  • 隨機數的產生取決於種子,隨機數和種子之間的關系遵從以下兩個規則:

    種子不同,產生不同的隨機數

    種子相同,即使實例不同也產生相同的隨機數

參數說明

   示例

# 作用:將數據集划分為 訓練集和測試集
# 格式:train_test_split(*arrays, **options)
from sklearn.mode_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
"""
參數
---
arrays:樣本數組,包含特征向量和標簽

test_size:
  float-獲得多大比重的測試樣本 (默認:0.25)
  int - 獲得多少個測試樣本

train_size: 同test_size

random_state:
  int - 隨機種子(種子固定,實驗可復現)
  
shuffle - 是否在分割之前對數據進行洗牌(默認True)

返回
---
分割后的列表,長度=2*len(arrays), 
  (train-test split)
"""

  

拆分參數遇到的問題及其解決方法

  導入模塊

from sklearn.cross_validation import cross_val_score

  則會報錯,代碼如下:

    from sklearn.cross_validation import cross_val_score
ModuleNotFoundError: No module named 'sklearn.cross_validation'

  解決方法:

from sklearn.model_selection import cross_val_score

  

4,定義模型

  在這一步我們首先要分析自己數據的類型,明白自己要用什么模型來做,然后我們就可以在sklearn中定義模型了,sklearn為所有模型提供了非常相似的接口,這樣使得我們可以更加快速的熟悉所有模型的用法,在這之前,我們先來看看模型的常用屬性和功能。

# 擬合模型
model.fit(X_train, y_train)
# 模型預測
model.predict(X_test)

# 獲得這個模型的參數
model.get_params()
# 為模型進行打分
model.score(data_X, data_y) # 線性回歸:R square; 分類問題: acc

  

4.1 線性回歸

from sklearn.linear_model import LinearRegression
# 定義線性回歸模型
model = LinearRegression(fit_intercept=True, normalize=False, 
    copy_X=True, n_jobs=1)

"""
參數
---
    fit_intercept:是否計算截距。False-模型沒有截距
    normalize: 當fit_intercept設置為False時,該參數將被忽略。 如果為真,
則回歸前的回歸系數X將通過減去平均值並除以l2-范數而歸一化。
     n_jobs:指定線程數
"""

  

4.2 邏輯回歸LR

from sklearn.linear_model import LogisticRegression
# 定義邏輯回歸模型
model = LogisticRegression(penalty=’l2’, dual=False, tol=0.0001, C=1.0, 
    fit_intercept=True, intercept_scaling=1, class_weight=None, 
    random_state=None, solver=’liblinear’, max_iter=100, multi_class=’ovr’, 
    verbose=0, warm_start=False, n_jobs=1)

"""參數
---
    penalty:使用指定正則化項(默認:l2)
    dual: n_samples > n_features取False(默認)
    C:正則化強度的反,值越小正則化強度越大
    n_jobs: 指定線程數
    random_state:隨機數生成器
    fit_intercept: 是否需要常量
"""

  

4.3 朴素貝葉斯算法NB(Naive Bayes)

from sklearn import naive_bayes
model = naive_bayes.GaussianNB() # 高斯貝葉斯
model = naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
model = naive_bayes.BernoulliNB(alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None)
"""
文本分類問題常用MultinomialNB
參數
---
    alpha:平滑參數
    fit_prior:是否要學習類的先驗概率;false-使用統一的先驗概率
    class_prior: 是否指定類的先驗概率;若指定則不能根據參數調整
    binarize: 二值化的閾值,若為None,則假設輸入由二進制向量組成
"""

  

 4.4 決策樹DT

from sklearn import tree 
model = tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None, 
    min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, 
    max_features=None, random_state=None, max_leaf_nodes=None, 
    min_impurity_decrease=0.0, min_impurity_split=None,
     class_weight=None, presort=False)
"""參數
---
    criterion :特征選擇准則gini/entropy
    max_depth:樹的最大深度,None-盡量下分
    min_samples_split:分裂內部節點,所需要的最小樣本樹
    min_samples_leaf:葉子節點所需要的最小樣本數
    max_features: 尋找最優分割點時的最大特征數
    max_leaf_nodes:優先增長到最大葉子節點數
    min_impurity_decrease:如果這種分離導致雜質的減少大於或等於這個值,則節點將被拆分。
"""

  

4.5 支持向量機SVM

from sklearn.svm import SVC
model = SVC(C=1.0, kernel=’rbf’, gamma=’auto’)
"""參數
---
    C:誤差項的懲罰參數C
    gamma: 核相關系數。浮點數,If gamma is ‘auto’ then 1/n_features will be used instead.
"""

  

4.6 k近鄰算法KNN

from sklearn import neighbors
#定義kNN分類模型
model = neighbors.KNeighborsClassifier(n_neighbors=5, n_jobs=1) # 分類
model = neighbors.KNeighborsRegressor(n_neighbors=5, n_jobs=1) # 回歸
"""參數
---
    n_neighbors: 使用鄰居的數目
    n_jobs:並行任務數
"""

  

4.7 多層感知器(神經網絡)

from sklearn.neural_network import MLPClassifier
# 定義多層感知機分類算法
model = MLPClassifier(activation='relu', solver='adam', alpha=0.0001)
"""參數
---
    hidden_layer_sizes: 元祖
    activation:激活函數
    solver :優化算法{‘lbfgs’, ‘sgd’, ‘adam’}
    alpha:L2懲罰(正則化項)參數。
"""

 

5,模型評估與選擇

  評價指標針對不同的機器學習任務有不同的指標,同一任務也有不同側重點的評價指標。以下方法,sklearn中都在sklearn.metrics類下,務必記住那些指標適合分類,那些適合回歸。

   機器學習常用的評估指標請參考博文:Python機器學習筆記:常用評估指標的前世今生

5.1 交叉驗證

交叉驗證cross_val_score的scoring參數

  • 分類:accuracy(准確率)、f1、f1_micro、f1_macro(這兩個用於多分類的f1_score)、precision(精確度)、recall(召回率)、roc_auc
  • 回歸:neg_mean_squared_error(MSE、均方誤差)、r2
  • 聚類:adjusted_rand_score、completeness_score等 

 

from sklearn.model_selection import cross_val_score
cross_val_score(model, X, y=None, scoring=None, cv=None, n_jobs=1)
"""參數
---
    model:擬合數據的模型
    cv : k-fold
    scoring: 打分參數-‘accuracy’、‘f1’、‘precision’、‘recall’ 、‘roc_auc’、'neg_log_loss'等等
"""

 

(補充):交叉驗證的學習

  1,導入k折交叉驗證模塊

  注意cross_val_score 是根據模型進行計算,計算交叉驗證的結果,可以簡單的認為cross_val_score中調用了KFold 進行數據集划分。

from sklearn.model_selection import cross_val_score

  2,交叉驗證的思想

  把某種意義下將原始數據(dataset)進行分組,一部分作為訓練集(train set),另一部分作為驗證集(validation set or test set),首先用訓練集對分類器進行訓練,再利用驗證集來測試訓練得到的模型(model),以此來作為評價分類器的性能指標。

  3,為什么使用交叉驗證法

  • 交叉驗證用於評估模型的預測性能,尤其是訓練好的模型在新數據上的表現,可以在一定程序熵減少過擬合。
  • 交叉驗證還可以從有限的數據中獲取盡可能多的有效信息

  4,model_selection.KFold 和 model_selection.cross_val_score的區別

  我們直接看官網:KFold:https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.KFold.html#sklearn.model_selection.KFold

    cross_val_score:https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html#sklearn.model_selection.cross_val_score

 

   KFold 就是對數據集划分為 訓練集/測試集,然后將訓練數據集划分為K折,每個折進行一次驗證,而剩下的K-1 折進行訓練,依次循環,直到用完所有的折。

 

   而 cross_val_score 就是通過交叉驗證評估得分

  下面看看K折交叉驗證函數KFold函數:

KFold(n_split, shuffle, random_state)

  參數:n_split:要划分的折數

     shuffle: 每次都進行shuffle,測試集中折數的總和就是訓練集的個數

     random_state:隨機狀態

   其使用如下:

from sklearn.model_selection import KFold
from sklearn.datasets import load_iris
from sklearn.linear_model import LinearRegression
import numpy as np
import pandas as pd

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([1, 2, 3, 4])
kf = KFold(n_splits=2)
# get_n_splits: Returns the number of splitting iterations in the cross-validator
print(kf.get_n_splits(X))  # 2

KF = KFold(n_splits=5)
X, Y = load_iris().data, load_iris().target
alg = LinearRegression()
# 這里想強行使用DataFrame的數據格式,因為以后大家讀取數據使用都是csv格式
# 所以必不可免要用 iloc
X, Y = pd.DataFrame(X), pd.DataFrame(Y)
# split():Generate indices to split data into training and test set.
for train_index, test_index in KF.split(X):
    print("TRAIN:", train_index, "TEST:", test_index)
    X_train, X_test = X.iloc[train_index], X.iloc[test_index]
    y_train, y_test = Y.iloc[train_index], Y.iloc[test_index]
    alg.fit(X_train, y_train)
    # 后面就自由發揮即可

 

  5,主要有哪些方法

1,留出法(holdout cross validation)

  在機器學習任務中,拿到數據后,我們首先會將原始數據集分為三部分:訓練集,驗證集和測試集。

  訓練集用於訓練模型,驗證集用於模型的參數選擇配置,測試集對於模型來說是未知數據,用於評估模型的泛化能力。

  這個方法操作簡單,只需要隨機將原始數據分為三組即可。

  不過如果只做一次分割,它對訓練集,驗證集和測試機的樣本比例,還有分割后數據的分布是否和原始數據集的分布相同等因素比較敏感,不同的划分會得到不同的最優模型,,而且分成三個集合后,用於訓練的數據更少了。於是又了2.k折交叉驗證(k-fold cross validation).

  下面例子,一共有150條數據:

>>> import numpy as np
>>> from sklearn.model_selection import train_test_split
>>> from sklearn import datasets
>>> from sklearn import svm

>>> iris = datasets.load_iris()
>>> iris.data.shape, iris.target.shape
((150, 4), (150,))

  用train_test_split來隨機划分數據集,其中40%用於測試集,有60條數據,60%為訓練集,有90條數據:

>>> X_train, X_test, y_train, y_test = train_test_split(
...     iris.data, iris.target, test_size=0.4, random_state=0)

>>> X_train.shape, y_train.shape
((90, 4), (90,))
>>> X_test.shape, y_test.shape
((60, 4), (60,))

  用train來訓練,用test來評價模型的分數。

>>> clf = svm.SVC(kernel='linear', C=1).fit(X_train, y_train)
>>> clf.score(X_test, y_test)                           
0.96...

  

2,2. k 折交叉驗證(k-fold cross validation)

 

   K折交叉驗證通過對k個不同分組訓練的結果進行平均來減少方差,因此模型的性能對數據的划分就不那么敏感。

  • 第一步,不重復抽樣將原始數據隨機分為 k 份。
  • 第二步,每一次挑選其中 1 份作為測試集,剩余 k-1 份作為訓練集用於模型訓練。
  • 第三步,重復第二步 k 次,這樣每個子集都有一次機會作為測試集,其余機會作為訓練集。
  • 在每個訓練集上訓練后得到一個模型,
  • 用這個模型在相應的測試集上測試,計算並保存模型的評估指標,
  • 第四步,計算 k 組測試結果的平均值作為模型精度的估計,並作為當前 k 折交叉驗證下模型的性能指標。

  K一般取10,數據量小的是,k可以設大一點,這樣訓練集占整體比例就比較大,不過同時訓練的模型個數也增多。數據量大的時候,k可以設置小一點。當k=m的時候,即樣本總數,出現了留一法。

  舉例,這里直接調用了cross_val_score,這里用了5折交叉驗證

>>> from sklearn.model_selection import cross_val_score
>>> clf = svm.SVC(kernel='linear', C=1)
>>> scores = cross_val_score(clf, iris.data, iris.target, cv=5)
>>> scores                                              
array([ 0.96...,  1.  ...,  0.96...,  0.96...,  1.        ])

  得到最后平均分數為0.98,以及它的95%置信區間:

>>> print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
Accuracy: 0.98 (+/- 0.03)

  我們可以直接看一下K-Fold是怎么樣划分數據的:X有四個數據,把它分成2折,結構中最后一個集合是測試集,前面的是訓練集,每一行為1折:

>>> import numpy as np
>>> from sklearn.model_selection import KFold

>>> X = ["a", "b", "c", "d"]
>>> kf = KFold(n_splits=2)
>>> for train, test in kf.split(X):
...     print("%s %s" % (train, test))
[2 3] [0 1]
[0 1] [2 3]

  同樣的數據X,我們來看LeaveOneOut后是什么樣子,那就是把它分成4折,結果中最后一個集合是測試集,只有一個元素,前面的是訓練集,每一行為1折:

>>> from sklearn.model_selection import LeaveOneOut

>>> X = [1, 2, 3, 4]
>>> loo = LeaveOneOut()
>>> for train, test in loo.split(X):
...     print("%s %s" % (train, test))
[1 2 3] [0]
[0 2 3] [1]
[0 1 3] [2]
[0 1 2] [3]

  

3,留一法(Leave one out cross validation)

  每次的測試集都只有一個樣本,要進行m次訓練和預測,這個方法用於訓練的數據只比整體數據集少一個樣本,因此最接近原始樣本的分布。但是訓練復雜度增加了,因為模型的數量與原始數據樣本數量相同。一般在數據缺少時使用。

此外:

  • 多次 k 折交叉驗證再求均值,例如:10 次 10 折交叉驗證,以求更精確一點。
  • 划分時有多種方法,例如對非平衡數據可以用分層采樣,就是在每一份子集中都保持和原始數據集相同的類別比例。
  • 模型訓練過程的所有步驟,包括模型選擇,特征選擇等都是在單個折疊 fold 中獨立執行的。

4,Bootstrapping

  通過自助采樣法,即在含有 m 個樣本的數據集中,每次隨機挑選一個樣本,再放回到數據集中,再隨機挑選一個樣本,這樣有放回地進行抽樣 m 次,組成了新的數據集作為訓練集。

  這里會有重復多次的樣本,也會有一次都沒有出現的樣本,原數據集中大概有 36.8% 的樣本不會出現在新組數據集中。

  優點是訓練集的樣本總數和原數據集一樣都是 m,並且仍有約 1/3 的數據不被訓練而可以作為測試集。 
  缺點是這樣產生的訓練集的數據分布和原數據集的不一樣了,會引入估計偏差。 
  (此種方法不是很常用,除非數據量真的很少)

 

5.2 檢驗曲線

  使用檢驗曲線,我們可以更加方便的改變模型參數,獲取模型表現。

from sklearn.model_selection import validation_curve
train_score, test_score = validation_curve(model, X, y, param_name, param_range, cv=None, scoring=None, n_jobs=1)
"""參數
---
    model:用於fit和predict的對象
    X, y: 訓練集的特征和標簽
    param_name:將被改變的參數的名字
    param_range: 參數的改變范圍
    cv:k-fold
   
返回值
---
   train_score: 訓練集得分(array)
    test_score: 驗證集得分(array)
"""

  

5.3 分類模型

  • accuracy_score(准確率得分)是模型分類正確的數據除以樣本總數 【模型的score方法算的也是准確率】
accuracy_score(y_test,y_pre)
# 或者 model.score(x_test,y_test),大多模型都是有score方法的

  

  • classification_report中的各項得分的avg/total 是每一分類占總數的比例加權算出來的
print(classification_report(y_test,y_log_pre))

             precision    recall  f1-score   support

          0       0.87      0.94      0.90       105
          1       0.91      0.79      0.85        73

avg / total       0.88      0.88      0.88       178

  

  • confusion_matrix(混淆矩陣),用來評估分類的准確性
>>> from sklearn.metrics import confusion_matrix
>>> y_true = [2, 0, 2, 2, 0, 1]
>>> y_pred = [0, 0, 2, 2, 0, 2]
>>> confusion_matrix(y_true, y_pred)
array([[2, 0, 0],
       [0, 0, 1],
       [1, 0, 2]])

  

  • precision_score(精確度)、recall_score(召回率)、f1_score(后者由前兩個推導出的)
這三個不僅適合二分類,也適合多分類。只需要指出參數average=‘micro’/‘macro’/'weighted’

    macro:計算二分類metrics的均值,為每個類給出相同權重的分值。
當小類很重要時會出問題,因為該macro-averging方法是對性能的平均。
另一方面,該方法假設所有分類都是一樣重要的,因此macro-averaging
方法會對小類的性能影響很大

    micro: 給出了每個樣本類以及它對整個metrics的貢獻的pair(sample-
weight),而非對整個類的metrics求和,它會每個類的metrics上的權重及
因子進行求和,來計算整個份額。Micro-averaging方法在多標簽(multilabel)
問題中設置,包含多分類,此時,大類將被忽略

    weighted: 對於不均衡數量的類來說,計算二分類metrics的平均,
通過在每個類的score上進行加權實現
  • roc_curve(ROC曲線,用於二分類)

 

6 保存模型

  最后,我們可以將我們訓練好的model保存到本地,或者放到線上供用戶使用,那么如何保存訓練好的model呢?主要有下面兩種方式:

6.1 保存為pickle文件

import pickle

# 保存模型
with open('model.pickle', 'wb') as f:
    pickle.dump(model, f)

# 讀取模型
with open('model.pickle', 'rb') as f:
    model = pickle.load(f)
model.predict(X_test)

  

6.2 sklearn自帶方法joblib

from sklearn.externals import joblib

# 保存模型
joblib.dump(model, 'model.pickle')

#載入模型
model = joblib.load('model.pickle')

  

7,模型評分

  1,模型的score方法:最簡單的模型評估方法就是調用模型自己的方法:

# 預測
y_predict = knnClf.predict(x_test)
print("score on the testdata:",knnClf.score(x_test,y_test))

  2,sklearn的指標函數:庫提供的一些計算方法,常用的有classification_report方法

  3,sklearn也支持自己開發評價方法。

 

8,幾種交叉驗證(cross validation)方式的比較

  模型評價的目的:通過模型評價,我們知道當前訓練模型的好壞,泛化能力如何?從而知道是否可以應用在解決問題上,如果不行,那又是那些出了問題?

train_test_split

  在分類問題中,我們通常通過對訓練集進行triain_test_split,划分出train 和test兩部分,其中train用來訓練模型,test用來評估模型,模型通過fit方法從train數據集中學習,然后調用score方法在test集上進行評估,打分;從分數上我們知道模型當前的訓練水平如何。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
import  matplotlib.pyplot as plt

cancer = load_breast_cancer()
X_train,X_test,y_train,y_test = train_test_split(cancer.data,cancer.target,random_state=0)

logreg = LogisticRegression().fit(X_train,y_train)
print("Test set score:{:.2f}".format(logreg.score(X_test,y_test)))

  結果:

Test set score:0.96

  然而這這方式只進行了一次划分,數據結果具有偶然性,如果在某次划分中,訓練集里全是容易學習的數據,測試集里全是復雜的數據,這樣的就會導致最終的結果不盡人意。

Standard Cross Validation

  針對上面通過train_test_split划分,從而進行模型評估方式存在的弊端,提出Cross Validation交叉驗證。

  Cross Validation:進行多次train_test_split划分;每次划分時,在不同的數據集上進行訓練,測試評估,從而得到一個評價結果;如果是5折交叉驗證,意思就是在原始數據集上,進行五次划分,每次划分進行一次訓練,評估,最后得到5次划分后的評估結果,一般在這幾次評估結果上取平均得到最后的評分,k-folf cross-validation ,其中K一般取5或10。

 

 代碼:

from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
import  warnings

warnings.filterwarnings('ignore')

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    cancer.data , cancer.target, random_state=0
)

logreg = LogisticRegression()
# CV 默認是3折交叉驗證,可以修改cv=5,變為5折交叉驗證
scores = cross_val_score(logreg,cancer.data , cancer.target)

print("Cross validation scores:{}".format(scores))
print("Mean cross validation score:{:2f}".format(scores.mean()))

  結果:

Cross validation scores:[0.93684211 0.96842105 0.94179894]
Mean cross validation score:0.949021

交叉驗證的優點:

  • 原始采用的train_test_split方法,數據划分具有偶然性;交叉驗證通過多次划分,大大降低了這種由一次隨機划分帶來的偶然性,同時通過多次划分,多次訓練,模型也能遇到各種各樣的數據,從而提高其泛化能力
  • 與原始的train_test_split相比,對數據的使用效率更高,train_test_split,默認訓練集,測試集比例為3:1,而對交叉驗證來說,如果是5折交叉驗證,訓練集比測試集為4:1;10折交叉驗證訓練集比測試集為9:1.數據量越大,模型准確率越高!

交叉驗證的缺點:

  這種簡答的交叉驗證方式,從上面的圖片可以看出來,每次划分時對數據進行均分,設想一下,會不會存在一種情況:數據集有5類,抽取出來的也正好是按照類別划分的5類,也就是說第一折全是0類,第二折全是1類,等等;這樣的結果就會導致,模型訓練時。沒有學習到測試集中數據的特點,從而導致模型得分很低,甚至為0,為避免這種情況,又出現了其他的各種交叉驗證方式。

Stratifid k-fold cross validation

  分層交叉驗證(Stratified k-fold cross validation):首先它屬於交叉驗證類型,分層的意思是說在每一折中都保持着原始數據中各個類別的比例關系,比如說:原始數據有3類,比例為1:2:1,采用3折分層交叉驗證,那么划分的3折中,每一折中的數據類別保持着1:2:1的比例,這樣的驗證結果更加可信。
通常情況下,可以設置cv參數來控制幾折,但是我們希望對其划分等加以控制,所以出現了KFold,KFold控制划分折,可以控制划分折的數目,是否打亂順序等,可以賦值給cv,用來控制划分。

 

代碼:

from sklearn.datasets import load_iris
from sklearn.model_selection import StratifiedKFold ,cross_val_score
from sklearn.linear_model import LogisticRegression
import warnings

warnings.filterwarnings('ignore')

iris_data = load_iris()
logreg = LogisticRegression()
strKFold = StratifiedKFold(n_splits=3,shuffle=False,random_state=0)
scores = cross_val_score(logreg,iris_data.data,iris_data.target,cv=strKFold)
print("straitified cross validation scores:{}".format(scores))
print("Mean score of straitified cross validation:{:.2f}".format(scores.mean()))

  

結果:

straitified cross validation scores:[0.96078431 0.92156863 0.95833333]
Mean score of straitified cross validation:0.95

  

Leave-one-out Cross-validation 留一法

  留一法Leave-one-out Cross-validation:是一種特殊的交叉驗證方式。顧名思義,如果樣本容量為n,則k=n,進行n折交叉驗證,每次留下一個樣本進行驗證。主要針對小樣本數據。

代碼:

from sklearn.datasets import load_iris
from sklearn.model_selection import LeaveOneOut , cross_val_score
from sklearn.linear_model import LogisticRegression
import  warnings

warnings.filterwarnings('ignore')

iris = load_iris()
logreg = LogisticRegression()
loout = LeaveOneOut()
scores = cross_val_score(logreg,iris.data,iris.target,cv=loout)
print("leave-one-out cross validation scores:{}".format(scores))
print("Mean score of leave-one-out cross validation:{:.2f}".format(scores.mean()))

  

結果:

leave-one-out cross validation scores:[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 0. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1.]
Mean score of leave-one-out cross validation:0.95

  

Shuffle-split cross-validation

  控制更加靈活,可以控制划分迭代次數,每次划分測試集和訓練集的比例(也就說:可以存在機不再訓練集也不再測試集的情況)

代碼:

from sklearn.datasets import load_iris
from sklearn.model_selection import ShuffleSplit,cross_val_score
from sklearn.linear_model import LogisticRegression
import warnings

warnings.filterwarnings('ignore')

iris = load_iris()
# 迭代八次
shufsp1 = ShuffleSplit(train_size=0.5,test_size=0.4,n_splits=8)
logreg = LogisticRegression()
scores = cross_val_score(logreg,iris.data,iris.target,cv=shufsp1)

print("shuffle split cross validation scores:\n{}".format(scores))
print("Mean score of shuffle split cross validation:{:.2f}".format(scores.mean()))

  

結果:

shuffle split cross validation scores:
[0.95       1.         0.86666667 0.95       0.88333333 0.88333333
 0.85       0.9       ]
Mean score of shuffle split cross validation:0.91

  

9,sklearn中一些函數的用法

9.1  from sklearn.utils import shuffle 解析

  在進行機器學習時,經常需要打亂樣本,這種時候Python中第三方庫提供了這個功能——sklearn.utils.shuffle。

1,Parameters

2,Returns

 



 

 

參考文獻:http://www.cnblogs.com/lianyingteng/p/7811126.html

https://www.cnblogs.com/magle/p/5638409.html

https://blog.csdn.net/u014248127/article/details/78885180

https://www.cnblogs.com/ysugyl/p/8707887.html


免責聲明!

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



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