机器学习
- [5.1 机器学习概述](#5.1 机器学习概述)
-
- [5.1.1 机器学习与人工智能](#5.1.1 机器学习与人工智能)
- [5.1.2 python机器学习方法库](#5.1.2 python机器学习方法库)
- [5.2 回归分析](#5.2 回归分析)
-
- [5.2.1 回归分析原理](#5.2.1 回归分析原理)
- [5.2.2 回归分析实现](#5.2.2 回归分析实现)
- [5.3 分类分析](#5.3 分类分析)
-
- [5.3.1 分类学习原理](#5.3.1 分类学习原理)
- [5.3.2 决策树](#5.3.2 决策树)
- [5.5.3 支持向量机](#5.5.3 支持向量机)
- [5.4 聚类分析](#5.4 聚类分析)
-
- [5.4.1 聚类任务](#5.4.1 聚类任务)
- [5.4.2 K-means算法](#5.4.2 K-means算法)
- [5.5 神经网络和深度学习](#5.5 神经网络和深度学习)
-
- 5.5.1神经元与感知器
- [5.5.2 神经网络](#5.5.2 神经网络)
- 5.5.3神经网络分类实现
课前:
- 如果忘了dataframe的操作的话,可阅读一下这一篇dataframe索引
我就补充一个点,那就是标签索引包含结束值,位置索引不包含。
主要的建模途径是使用机器学习的算法,让计算机从数据中自主学习产生模型
5.1 机器学习概述
5.1.1 机器学习与人工智能
具体的介绍请见:机器学习与深度学习
机器学习分类:
- 有监督的学习:利用经验,学习表示事物的模型,关注利用模型预测未来数据
- 分类问题:对事物所属类型的判别,类型的数量是已知的
- 回归问题:预测目标是连续变量
- 无监督的学习:倾向于对事物本身特性的分析
- 数据降维:对描述事物的特征数量进行压缩的方法
- 聚类问题:将事物划分成不同的类别(与分类不同之处是事先不知道类别的数量,他根据事物之间的相似性,将相似的事物归为一簇
5.1.2 python机器学习方法库
我们接下来讲的主要使用的是scikit-learn
5.2 回归分析
5.2.1 回归分析原理
通过样本学习目标变量和自变量之间的因果关系,建立数学表示模型,基于新的自变量,此模型可预测相应的目标变量
y:目标变量
{x1,x2,x3,x4...xd}:自变量
d:自变量的维度
- 回归模型的学习大致是,我们给一个函数表达式,这个表达式有很多模型参数{w1,w2,w3,w4...wd,b}:w1是回归系数,b为截距,注意:x,y在训练过程中都是已知的,未知的是回归系数和截距。
5.2.2 回归分析实现
下面我们用线性回归作为例子。
1)先导入数据
python
import numpy as np
import pandas as pd
filename = 'data\...\...'
data = pd.read_csv(filename,index_col = 0)
#index_col是选择一列作为行索引,如果没写会默
#认新的一列(123456)作为索引,而header是默认
#用第一列的,这两者还是有区别的
2)整理数据
python
X = data.iloc[:,0:3].values.astype(float)
#这里的0:3是不包括索引列的
Y = data.iloc[:,3].values.astype(float)
一定要用values,因为我们后面只能对ndarray操作,dataframe不行。使用 astype(float) 的目的通常是保证数据的类型一致性,尤其是在进行数值计算和机器学习建模时,确保所有的数据都是浮点数,有助于避免因数据类型不匹配而引发的错误。同时,将数据转换为浮点数也可以提高计算的准确性,尤其在处理很小的数值时。
3)划分数据集
python
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test =model_selection.train_test_split(x,y,test_size = 0.35.random_state = 1)
test_size是测试集的比例,random_state确定下来可以让每次的训练集和测试集都是固定的。
4)训练学习模型
python
from sklearn.linear_model import LinearRegression
linreg = LinearRegression()
linreg.fit(x_train,y_train)
print(linreg.intercept_,linregTr.coef_)
#intercept_是截距,coef_是回归系数
5)在测试集上应用模型,计算预测结果。
python
y_test_pred = linregTr.predict(x_test)
6)计算RMSE和决定系数R^2^
python
from sklearn import metrics
test_err = metrics.mean_squared_error(y_test,y_test_pred)#均方误差
predict_score = linregTr.score(x_test,y_test)#在测试集上计算决定系数
7)保存模型以供以后使用
python
import joblib
joblib.dump(linreg,'文件名')
8)重新加载
python
load_linreg = joblib.load('文件名')
这里还要注意均方误差的参数是y的实际值以及y的预测值(因为就是对他们的差集做平方和相加),其实就相当于一个数学公式,与f没什么关系其实
而决定系数的参数是x的实际值和y的实际值,因为可以看到他是用linregt算的,这个linregt以及是一个固定的函数了,所以也默认包含了y的实际值等信息,所以这个时候你只要把x和y输入就可以判断这个准不准了
一些更细节的描述大家可以看我的另外一篇文章线性回归
完整可运行代码如下:
数据样子:
python
#1.导入数据
import numpy as np
import pandas as pd
filename = 'advertising.csv'
data = pd.read_csv(filename,index_col=0)
print(data.head())
#2.绘图看关系(可有可无,用于筛选哪些因素会更多的影响目标变量)
import matplotlib.pyplot as plt
data.plot(kind = 'scatter',x = 'TV',y = 'Sales',title = 'Sales by TV')
plt.xlabel('TV Advertising')
plt.ylabel('Sales')
plt.show()
#3.处理数据,分割数据
x = data.iloc[:,0:3].values.astype(float)
y = data.iloc[:,3].values.astype(float)
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
#4.训练模型
from sklearn.linear_model import LinearRegression
linreg = LinearRegression()
linreg.fit(x_train,y_train)
print(linreg.intercept_,linreg.coef_)
#5.保存模型
import joblib
joblib.dump(linreg, 'model.pkl')
load_linreg = joblib.load('model.pkl')
#6.导入模型
y_test_pred = load_linreg.predict(x_test)
#7.评估模型,算均方差和决定系数
from sklearn import metrics
test_err = metrics.mean_squared_error(y_test,y_test_pred)
test_score = linreg.score(x_test,y_test)
print(test_err)
print(test_score)
要注意一下是import joblib,以前老版本不是这个,要注意!!
总结:
- 线性回归的测试用的是score(用模型调用),以及mean_squared_error为均方根误差(用metrics调用),针对测试y和y的计算值
- 训练模型要先声明类,然后再fit数据
- 线性回归的数据记得要变为ndarray类型,这样模型才可以处理,然后要划分数据集。
5.3 分类分析
5.3.1 分类学习原理
预测的结果可以是二分类问题,也可以是多分类问题。数据集中每条数据包括多个特征项,以及一个分类标签,分类算法通过数据集自动学习分类模型。常见的分类学习算法很多,接下来我们会介绍决策树和SVM
性能评估:混淆矩阵,如下图
基于混淆矩阵,准确率:所有数据中被正确预测的比例
精确率:计算预测为yes类的样本中,比例为yes的比例
召回率:真实值为yes的样本中,被正确预测的比例
F1:以及上述的调和平均值。
5.3.2 决策树
1.决策树原理
来源于人们在面临决策问题时候的一种自然的思考过程
该决策树讲样本的特征值作为节点,用特征的取值作为分支
叶子节点对应于结果,其他节点对应于一个测试
2.决策树分类实现
python
1)导入数据
import numpy as np
import pandas as pd
filename = 'bankdebt.csv'
data = pd.read_csv(filename,index_col=0,header=None)
#nrows是先读取的行数
print(data.head())
'''
1 2 3 4
0
1 Yes Single 12.5 No
2 No Married 10.0 No
3 No Single 7.0 No
4 Yes Married 12.0 No
5 No Divorced 9.5 Yes
'''
2)训练分类器模型的时候,参数为数值型数组,
# 需要将样本中的字符型转化为数字,统一将'yes'转化
# 为1,'No'替换成0,single替换为1,married替换为2,divorced替换为3
data.loc[data[1] == 'Yes',1] = 1
#注意,这里的data[1]默认用的是系统给我们
# 提供的那一行标签名,等同于data.iloc[:,0]
data.loc[data[1] == 'No',1] = 0
data.loc[data[4] == 'Yes',4] = 1
data.loc[data[4] == 'No',4] = 0
data.loc[data[2] == 'Single',2]=1
data.loc[data[2] == 'Married',2]=2
data.loc[data[2] == 'Divorced',2] =3
print(data.head())
'''
1 2 3 4
0
1 1 1 12.5 0
2 0 2 10.0 0
3 0 1 7.0 0
4 1 2 12.0 0
5 0 3 9.5 1
'''
3)数据集分配
x = data.loc[:,1:3].values.astype(float)
y = data.loc[:,4].values.astype(int) #决策树的目标变量要为整形
4)训练模型
from sklearn import tree
clf = tree.DecisionTreeClassifier()
clf = clf.fit(x,y)
5)性能评估
predicted_y = clf.predict(x)
from sklearn import metrics
accuracy =clf.score(x_test, y_test)
print(metrics.classification_report(y,predicted_y))
#注意:classification_report只能用于分类问题,下面的混淆矩阵也是
print(metrics.confusion_matrix(y,predicted_y))
'''
precision recall f1-score support
0 1.00 1.00 1.00 10
1 1.00 1.00 1.00 5
accuracy 1.00 15
macro avg 1.00 1.00 1.00 15
weighted avg 1.00 1.00 1.00 15
[[10 0]
[ 0 5]]
'''
为什么我上面的评估那么好,因为我用的全是训练集啊!
总结:
- 分类器模型的参数都要转化为数值型!!!!但是要注意输入变量x要astype为float,输出变量要astype为int
- 分类的性能评估一般是看分类报告和混淆矩阵(都是用metrics调用,传入predicted_y和y_test),以及score---->前面写线性回归的时候也有提到score,(这里简单科普一下:对于分类任务,score函数返回的是模型在测试数据集上的准确率(即正确分类的样本数占总样本数的比例)。而对于回归任务,score函数则通常返回模型的决定系数(R²值),衡量模型对数据变异性的解释能力。)
- 可以简单总结一下,score函数一般由模型本身调用,其他评估方法一般由metrics调用
5.5.3 支持向量机
基本原理介绍:将数据看作多维空间的点,求解一个最优的超平面,将两种不同类别的点分割开来。有些数据集在低维空间无法使用超平面进行划分,但将其映射到高维空间中,则能找到一个超平面将不同类的点分隔开。SVM采用核函数将低维数据映射到高维空间,选用适当的核函数就可以得到高维的分割平面。
下面是具体的实现:
python
import numpy as np
import pandas as pd
1)导入数据
filename = 'bankpep.csv'
data = pd.read_csv(filename,index_col=0)
2)svm只能使用数值型变量进行输入
'''
id,age,sex,region,income,married,children,car,save_act,current_act,mortgage,pep
ID12111,66,FEMALE,TOWN,59803.9,YES,0,NO,YES,YES,NO,NO
ID12112,52,FEMALE,INNER_CITY,26658.8,NO,0,YES,YES,YES,YES,NO
ID12113,44,FEMALE,TOWN,15735.8,YES,1,NO,YES,YES,YES,YES
ID12114,66,FEMALE,TOWN,55204.7,YES,1,YES,YES,YES,YES,YES
ID12115,36,MALE,RURAL,19474.6,YES,0,NO,YES,YES,YES,NO
ID12116,38,FEMALE,INNER_CITY,22342.1,YES,0,YES,YES,YES,YES,NO
ID12117,37,FEMALE,TOWN,17729.8,YES,2,NO,NO,NO,YES,NO
可以看出来yes的列还是很多的,可以一次性处理。
'''
seq = ['married','car','save_act','current_act','mortgage','pep']
pd.set_option('display.max_rows', None) #这样可以显示全部
pd.set_option('display.max_columns', None)
for feature in seq:
data.loc[data[feature]=='YES',feature] = 1
data.loc[data[feature]=='NO',feature] = 0
data.loc[data['sex']=='FEMALE','sex'] = 1
data.loc[data['sex']=='MALE','sex'] =0
3)化为独热编码
'''
age sex region income married children car save_act \
id
ID12101 48 1 INNER_CITY 17546.0 0 1 0 0
ID12102 40 0 TOWN 30085.1 1 3 1 0
ID12103 51 1 INNER_CITY 16575.4 1 0 1 1
ID12104 23 1 TOWN 20375.4 1 3 0 0
ID12105 57 1 RURAL 50576.3 1 0 0 1
可见region,child的取值都超过两个,且没有大小意义,采用独热编码。
'''
dumm_reg = pd.get_dummies(data['region'],prefix='region')
dumm_child = pd.get_dummies(data['children'],prefix='children')
df1 = data.drop(['region','children'],axis = 1)
df2 = df1.join([dumm_reg,dumm_child],how = 'outer')
sep1= ['region_INNER_CITY','region_RURAL','region_SUBURBAN','region_TOWN',
'children_0','children_1','children_2','children_3']
for feature in sep1:
df2[feature].astype(int)
4)取出训练数据
x = df2.drop(['pep'],axis=1).values.astype(float)
y = df2['pep'].values.astype(int)
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)
'''
在支持向量机(SVM)中,目标变量 y必须是整数,因为 SVM 是一种监督学习算法,通常
用于分类任务。分类任务的目标是将数据点分配到不同的类别中,而类别通常用整数来表示。
'''
print(df2.head())
5)训练模型
from sklearn import svm
clf = svm.SVC(kernel = 'rbf',gamma = 0.6,C = 100)
clf.fit(x_train,y_train)
6)评估模型
print(clf.score(x_train,y_train))
print(clf.score(x_test,y_test))#发现效果极差
7)SVM算法需要计算样本点之间的距离,为了保证样本各个特征项对距离
计算的贡献相同,需要对数值型数据做标准化处理
from sklearn import preprocessing
x_scale = preprocessing.scale(x)
xtrain,xtest,ytrain,ytest = train_test_split(x_scale,y,test_size=0.3,random_state=1)
clf = svm.SVC(kernel = 'rbf',gamma = 0.7,C = 1.0)
clf.fit(xtrain,ytrain)
print(clf.score(xtrain,ytrain))
print(clf.score(xtest,ytest))
from sklearn import metrics
y_predicted = clf.predict(x_test)
print(metrics.classification_report(y_test,y_predicted))
pd.get_dummies(data['region'],prefix = 'region') //要记住,考试不给
svm.SVC的参数如下:
kernel:使用的核函数。linear为线性核函数,poly为多项式核函数,rbf为高斯核函数,sigmoid为logistic核函数
gamma,一般取值(0,1)
C:误差项的惩罚参数,一般取10^n^
pd.set_option('display.max_rows', None) #这样可以显示全部pd.set_option('display.max_columns', None)
总结:
- 学习到了转化独热编码的方法get_dummies(由pandas调用),记得drop后再join
- svm其特殊处在于由于他是靠计算数字之间的距离,所以要先标准化。再去分割数据集
5.4 聚类分析
5.4.1 聚类任务
区别于监督学习训练样本包含目标值,而聚类分析这类是没有目标值的,只能根据数据内在性质以及规律将其划分为若干个不相交的子集,每个子集为一个簇。
聚类算法会自动形成簇结构,但是并不知道它对于哪个类别名,还想不要使用者来辨别。
5.4.2 K-means算法
K-means是划分法中的经典算法。划分法的基本目标是:将数据聚为若干簇,簇内的点都足够近,簇间的点都足够远,它通过计算数据集中样本之间的距离,根据距离的远近将其划分为多个簇。
K-means过程如下:
- 首先假定划分的簇数k,然后从数据集任选k个作为各簇的中心。
- 计算样本与簇中心的距离相似度,将数据集中的每个样本划分到与其最相似的一个簇。
- 计算每个簇的中心(重新算)
- 不断重复这一过程直到中心不再发生变化。
K-means算法核心是相似度的计算,如果数据样本的特征值主要是数值型数据,欧式距离是最简单的选择,通常为了去除不同特征数据值范围不一致带来的影响,数据要先进行标准化处理。
如果是离散化数据,则采用余弦相似度更为合适。因为后面的代码都有具体的实现,所以我也不过多介绍这些方法,这是数学系的内容了。
现在我来写一下具体的实现:
python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#1)读取数据
filename = 'iris.data'
data = pd.read_csv(filename, header=None)
data.columns = ['sepal length', 'sepal width', 'petal length', 'petal width','class']
'''
sepal length sepal width petal length petal width class
0 5.1 3.5 1.4 0.2 Iris-setosa
1 4.9 3.0 1.4 0.2 Iris-setosa
2 4.7 3.2 1.3 0.2 Iris-setosa
3 4.6 3.1 1.5 0.2 Iris-setosa
4 5.0 3.6 1.4 0.2 Iris-setosa
'''
#2)我们想要决定有几簇,但是四维空间确实不好确定,所以我们绘
# 制散点图矩阵来观察每两种特征的区分度。
pd.plotting.scatter_matrix(data,diagonal = 'hist')
plt.show()
#3)取前四列特征值作为训练数据,定义簇的数目为3
x = data.iloc[:,0:4].values.astype(float)
#4)训练模型
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3)
kmeans.fit(x)
#5)k-means 模型的参数lables_给出参与训练的每个样本的簇标签。
# 使用样本簇编号作为类型标签,可以绘制特征对的散点图矩阵,用不
# 同的颜色表示不同的簇
pd.plotting.scatter_matrix(data,c = kmeans.labels_,diagonal = 'hist')
plt.show()
#6)评估
'''
1.有分类标签的数据集
使用兰德指数评价聚类性能,
他计算真实标签和聚类标签
之间的相似性,取值范围为【0,1】
'''
from sklearn import metrics
data.loc[data['class']=='Iris-setosa','class'] = 0
data.loc[data['class']=='Iris-versicolor','class'] = 1
data.loc[data['class']=='Iris-virginica','class'] = 2
y = data['class'].values.astype(int)
print(metrics.adjusted_rand_score(y,kmeans.labels_))
'''
2.没有分类标签
常用轮廓系数来衡量聚类的质量,轮廓系数同时
考虑聚类结果的簇内凝聚度和簇间分离值,取值
范围为【-1,1】,轮廓系数越大,表示聚类效果越好
'''
metrics.silhouette_score(x,kmeans.labels_,metric='euclidean')
我们上面其实忽略了一个细节,就是怎么确定簇数
python
#确定簇数
clusters = [2,3,4,5,6,7,8]
sc_score = []
for i in clusters:
kmeans = KMeans(n_clusters=i).fit(x)
sc = metrics.silhouette_score(x,kmeans.labels_,metric='euclidean')
sc_score.append(sc)
plt.plot(clusters,sc_score,'*-')
plt.xlabel('Number of clusters')
plt.ylabel('Silhouette score')
plt.show()
可见两簇的效果是最好的
关于兰德系数:
标签化为数字的原因及好处:
1在聚类中,标签用数字(如0, 1, 2)表示不同的簇。
好处:
简洁性:数字标签简单、易于处理。
计算效率:数字运算比字符串操作更高效。
一致性:便于与其他算法和指标(如调整后的兰德系数)进行比较。
2兰德系数的计算:
兰德系数用于衡量两个分区(例如,真实标签和聚类结果)之间的相似性。
关注点在于数据点对是否在同一个簇中,而非标签的具体数值。
3传入标签的必要性:
需要传入标签以明确每个数据点属于哪个簇,从而进行一致性计算。
这使得我们可以比较不同的分区方案。
4聚类标签与真实标签的关系:
聚类标签由算法生成,表示每个数据点所属的簇。
标签的具体数字与真实标签的数字无关,只是用于区分不同的簇。
什么意思呢?就是说我们把y化成具体数字,即使这些数字与聚类算法算出来的数字不一样也没关系,数字的值不重要,同属于一个数字值才重要,这是兰德系数的底层原理。
轮廓系数(Silhouette Score)定义:
轮廓系数是用来评估聚类质量的一个指标。它结合了凝聚度和分离度。
计算方法:
凝聚度(a):
对于每个数据点,计算它与同簇其他点的平均距离。
这个值越小越好,表示簇内的点越接近。
分离度(b):
对于每个数据点,计算它与最近的其他簇的平均距离。
这个值越大越好,表示不同簇之间的点越远。
轮廓系数(s):
轮廓系数的范围是 [-1, 1]。
--->接近1表示良好的聚类:簇内凝聚,簇间分离。
--->接近0表示重叠的簇。
--->负值表示可能的错误聚类。
好处:
直观:提供一个简单的数值来表示聚类质量。
无监督:不需要真实标签,适用于评估任何聚类结果。
通过轮廓系数,我们可以判断聚类结果是否合理,帮助选择合适的簇数。
总结:
- 由于聚类和前面的svm一样都要计算数值,所以前面的时候数据也可以用scale标准化一下
- 聚类分析经常要画散点图矩阵,记住这个表达
pd.plotting.scatter_matrix(data,diagonal = 'hist')
, - 当聚类分析有标签时候,用兰德系数adjusted_rand_score来评估
- 当聚类分析无标签的时候,用轮廓系数silhouette_score来评估
- 注意评估前先把目标y转化为数字,是多少不重要
5.5 神经网络和深度学习
5.5.1神经元与感知器
人造神经元就叫做感知器。接受多个输入,产生一个输出
5.5.2 神经网络
神经网络的学习过程就是根据训练数据集来调整神经元之间的连接权重,以及每个神经元的偏置项,使得最终输出层能够更好的拟合训练集的真实值。
5.5.3神经网络分类实现
python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
1)获取数据以及分析数据
filename = 'iris.data'
data = pd.read_csv(filename,header=None)
data.columns = ['sepal length', 'sepal width', 'petal length', 'petal width','class']
print(data['class'].value_counts())
'''
Iris-setosa 50
Iris-versicolor 50
Iris-virginica 50
'''
print(data.groupby('class').mean())
print(data.groupby('class').var())
'''
sepal length sepal width petal length petal width
class
Iris-setosa 5.006 3.418 1.464 0.244
Iris-versicolor 5.936 2.770 4.260 1.326
Iris-virginica 6.588 2.974 5.552 2.026
sepal length sepal width petal length petal width
class
Iris-setosa 0.124249 0.145180 0.030106 0.011494
Iris-versicolor 0.266433 0.098469 0.220816 0.039106
Iris-virginica 0.404343 0.104004 0.304588 0.075433
'''
2)数据预处理
'''
MLPClassifier的分类器训练函数y的值可以是整数,用于实现多分类
'''
data.loc[data['class']=='Iris-setosa','class'] = 0
data.loc[data['class']=='Iris-versicolor','class'] = 1
data.loc[data['class']=='Iris-virginica','class'] = 2
x = data.iloc[:,0:4].values.astype(float)
y = data.iloc[:,4].values.astype(int) #用于分类的astype基本都是int
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
3)训练模型
from sklearn.neural_network import MLPClassifier
mlp = MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(5,5), random_state=1)
mlp.fit(x,y)
print(mlp.score(x,y))
'''
solver为优化权重的算法{lbfgs,sgd,adam}
activation为激活函数,{identity,logistic,tanh,relu}默认relu
hidden_layer_sizes:神经网络结构,eg(5,10,5)表示三层,每层节点为5,10,5
alpha:正则化参数
max_iter:最大迭代次数,bp算法(反向传播算法)的学习次数
random_state:随机数种子
'''
4)分类器性能评估
from sklearn import metrics
y_predicted = mlp.predict(x_test)
print("--------------下面是分类器的报告和混淆矩阵------------------")
print(metrics.classification_report(y_test, y_predicted))
print(metrics.confusion_matrix(y_test, y_predicted))
温故而知新。groupby,看我的这篇文章groupby详解
生活有时会让我们感到疲惫,但请记住,每一个挑战都是成长的机会。你拥有无限的潜力,每一次的努力都在为未来的成功铺路。不要害怕困难,因为它们塑造了你的坚韧和毅力。当你感到疲惫时,深呼吸,给自己一点时间休息和恢复。学习路上,书籍和知识陪伴,你不孤单!