一、 机器学习介绍与定义
1. 机器学习定义
机器学习(Machine Learning)本质上就是让计算机自己在数据中学习规律,并根据所得到的规律对未来数据进行预测。
机器学习包括如聚类、分类、决策树、贝叶斯、神经网络、深度学习(Deep Learning)等算法。
机器学习的基本思路是模仿人类学习行为的过程,如我们在现实中的新问题一般是通过经验归纳,总结规律,从而预测未来的过程。机器学习的基本过程如下:
2. 机器学习的发展历史
从机器学习发展的过程上来说,其发展的时间轴如下所示:
从上世纪50年代的图灵测试提出、塞缪尔开发的西洋跳棋程序,标志着机器学习正式进入发展期。
60年代中到70年代末的发展几乎停滞。
80年代使用神经网络反向传播(BP)算法训练的多参数线性规划(MLP)理念的提出将机器学习带入复兴时期。
90年代提出的“决策树”(ID3算法),再到后来的支持向量机(SVM)算法,将机器学习从知识驱动转变为数据驱动的思路。
21世纪初Hinton提出深度学习(Deep Learning),使得机器学习研究又从低迷进入蓬勃发展期。
从2012年开始,随着算力提升和海量训练样本的支持,深度学习(Deep Learning)成为机器学习研究热点,并带动了产业界的广泛应用。
3. 机器学习分类
机器学习经过几十年的发展,衍生出了很多种分类方法,这里按学习模式的不同,可分为监督学习、半监督学习、无监督学习和强化学习。
3.1 监督学习
监督学习(Supervised Learning)是从有标签的训练数据中学习模型,然后对某个给定的新数据利用模型预测它的标签。如果分类标签精确度越高,则学习模型准确度越高,预测结果越精确。
监督学习主要用于回归和分类。
常见的监督学习的回归算法有线性回归、回归树、K邻近、Adaboost、神经网络等。
常见的监督学习的分类算法有朴素贝叶斯、决策树、SVM、逻辑回归、K邻近、Adaboost、神经网络等。
3.2 半监督学习
半监督学习(Semi-Supervised Learning)是利用少量标注数据和大量无标注数据进行学习的模式。
半监督学习侧重于在有监督的分类算法中加入无标记样本来实现半监督分类。
常见的半监督学习算法有Pseudo-Label、Π-Model、Temporal Ensembling、Mean Teacher、VAT、UDA、MixMatch、ReMixMatch、FixMatch等。
3.3 无监督学习
无监督学习(Unsupervised Learning)是从未标注数据中寻找隐含结构的过程。
无监督学习主要用于关联分析、聚类和降维。
常见的无监督学习算法有稀疏自编码(Sparse Auto-Encoder)、主成分分析(Principal Component Analysis, PCA)、K-Means算法(K均值算法)、DBSCAN算法(Density-Based Spatial Clustering of Applications with Noise)、最大期望算法(Expectation-Maximization algorithm, EM)等。
3.4 强化学习
强化学习(Reinforcement Learning)类似于监督学习,但未使用样本数据进行训练,是是通过不断试错进行学习的模式。
在强化学习中,有两个可以进行交互的对象:智能体(Agnet)和环境(Environment),还有四个核心要素:策略(Policy)、回报函数(收益信号,Reward Function)、价值函数(Value Function)和环境模型(Environment Model),其中环境模型是可选的。
强化学习常用于机器人避障、棋牌类游戏、广告和推荐等应用场景中。
为了便于读者理解,用灰色圆点代表没有标签的数据,其他颜色的圆点代表不同的类别有标签数据。监督学习、半监督学习、无监督学习、强化学习的示意图如下所示:
4. 机器学习需要具备的基础的知识,如何学习机器学习
机器学习涉及到线性代数、微积分、概率和统计。
学习机器学习需要掌握一定的数学和编程基础。以下是一些建议,帮助您开始学习机器学习:
学习数学基础:了解线性代数、概率论和统计学等数学概念。这些概念在机器学习中非常重要,可以帮助您理解算法和模型背后的原理。
学习编程语言:掌握至少一种常用的编程语言,如Python或R。这些语言在机器学习中广泛使用,具有丰富的机器学习库和工具。
学习机器学习算法:了解常见的机器学习算法,如线性回归、决策树、支持向量机、神经网络等。学习它们的原理、应用和优缺点。
学习机器学习工具和框架:熟悉常用的机器学习工具和框架,如scikit-learn、TensorFlow、PyTorch等。掌握它们的使用方法和基本操作。
实践项目:通过实践项目来应用所学的知识。选择一些小型的机器学习项目,从数据收集和预处理到模型训练和评估,逐步提升自己的实践能力。
学习资源:利用在线教程、课程、书籍和开放资源来学习机器学习。有很多免费和付费的学习资源可供选择,如Coursera、Kaggle、GitHub上的机器学习项目等。
参与机器学习社区:加入机器学习社区,与其他学习者和专业人士交流经验和学习资源。参与讨论、阅读博客、参加线下活动等,扩展自己的学习网络。
持续学习和实践:机器学习是一个不断发展的领域,保持学习的态度并持续实践非常重要。跟随最新的研究成果、参与竞赛和项目,不断提升自己的技能。
记住,机器学习是一个广阔的领域,需要不断的学习和实践才能掌握。持续投入时间和精力,逐步积累经验和知识,便会逐渐掌握机器学习的技能。
5 机器学习的应用场合
机器学习的应用场景非常广泛,几乎涵盖了各个行业和领域。以下是一些常见的机器学习应用场景的示例:
-
自然语言处理(NLP)
自然语言处理是人工智能中的重要领域之一,涉及计算机与人类自然语言的交互。NLP技术可以实现语音识别、文本分析、情感分析等任务,为智能客服、聊天机器人、语音助手等提供支持。
-
医疗诊断与影像分析
机器学习在医疗领域有着广泛的应用,包括医疗图像分析、疾病预测、药物发现等。深度学习模型在医疗影像诊断中的表现引人注目。
-
金融风险管理
机器学习在金融领域的应用越来越重要,尤其是在风险管理方面。模型可以分析大量的金融数据,预测市场波动性、信用风险等。
-
预测与推荐系统
机器学习在预测和推荐系统中也有广泛的应用,如销售预测、个性化推荐等。协同过滤和基于内容的推荐是常用的技术。
-
制造业和物联网
物联网(IoT)在制造业中的应用越来越广泛,机器学习可用于处理和分析传感器数据,实现设备预测性维护和质量控制。
-
能源管理与环境保护
机器学习可以帮助优化能源管理,减少能源浪费,提高能源利用效率。通过分析大量的能源数据,识别优化的机会。
-
决策支持与智能分析
机器学习在决策支持系统中的应用也十分重要,可以帮助分析大量数据,辅助决策制定。基于数据的决策可以更加准确和有据可依。
-
图像识别与计算机视觉
图像识别和计算机视觉是另一个重要的机器学习应用领域,它使计算机能够理解和解释图像。深度学习模型如卷积神经网络(CNN)在图像分类、目标检测等任务中取得了突破性进展。
6. 机器学习趋势分析
机器学习正真开始研究和发展应该从80年代开始,深度神经网络(Deep Neural Network)、强化学习(Reinforcement Learning)、卷积神经网络(Convolutional Neural Network)、循环神经网络(Recurrent Neural Network)、生成模型(Generative Model)、图像分类(Image Classification)、支持向量机(Support Vector Machine)、迁移学习(Transfer Learning)、主动学习(Active Learning)、特征提取(Feature Extraction)是机器学习的热点研究。
以深度神经网络、强化学习为代表的深度学习相关的技术研究热度上升很快,近几年仍然是研究热点。
7. 机器学习项目开发步骤
有5个基本步骤用于执行机器学习任务:
-
收集数据:无论是来自excel,access,文本文件等的原始数据,这一步(收集过去的数据)构成了未来学习的基础。相关数据的种类,密度和数量越多,机器的学习前景就越好。
-
准备数据:任何分析过程都会依赖于使用的数据质量如何。人们需要花时间确定数据质量,然后采取措施解决诸如缺失的数据和异常值的处理等问题。探索性分析可能是一种详细研究数据细微差别的方法,从而使数据的质量迅速提高。
-
练模型:此步骤涉及以模型的形式选择适当的算法和数据表示。清理后的数据分为两部分 - 训练和测试(比例视前提确定); 第一部分(训练数据)用于开发模型。第二部分(测试数据)用作参考依据。
-
评估模型:为了测试准确性,使用数据的第二部分(保持/测试数据)。此步骤根据结果确定算法选择的精度。检查模型准确性的更好测试是查看其在模型构建期间根本未使用的数据的性能。
-
提高性能:此步骤可能涉及选择完全不同的模型或引入更多变量来提高效率。这就是为什么需要花费大量时间进行数据收集和准备的原因。
无论是任何模型,这5个步骤都可用于构建技术,当我们讨论算法时,您将找到这五个步骤如何出现在每个模型中!
二、scikit-learn工具介绍
-
Python语言机器学习工具
-
Scikit-learn包括许多智能的机器学习算法的实现
-
Scikit-learn文档完善,容易上手,丰富的API接口函数
-
Scikit-learn官网:scikit-learn: machine learning in Python — scikit-learn 1.6.1 documentation
-
Scikit-learn中文文档:sklearn
1 scikit-learn安装
参考以下安装教程:https://www.sklearncn.cn/62/
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scikit-learn
2 Scikit-learn包含的内容
三 数据集
1 sklearn玩具数据集介绍
数据量小,数据在sklearn库的本地,只要安装了sklearn,不用上网就可以获取
2 sklearn现实世界数据集介绍
3 sklearn加载玩具数据集
示例1:鸢尾花数据
from sklearn.datasets import load_iris
iris = load_iris()#鸢尾花数据
鸢尾花数据集介绍
特征有:
花萼长 sepal length
花萼宽sepal width
花瓣长 petal length
花瓣宽 petal width
三分类:
0-Setosa山鸢尾
1-versicolor变色鸢尾
2-Virginica维吉尼亚鸢尾
from sklearn.datasets import load_iris
iris = load_iris() #返回一个Bunch对象
iris字典中有几个重要属性:
# data 特征
# feature_names 特征描述
# target 目标
# target_names 目标描述
# DESCR 数据集的描述
# filename 下后到本地保存后的文件名
print(iris.data)#得到特征
print(iris.feature_names) #特征描述
print(iris.target) #目标形状
print(iris.target_names)#目标描述
print(iris.filename) #iris.csv 保存后的文件名
print(iris.DESCR)#数据集的描述
下面使用pandas把特征和目标一起显示出来
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
iris = load_iris()
feature = iris.data
target = iris.target
target.shape=(len(target), 1)
data = np.hstack([feature, target])
cols = iris.feature_names
cols.append("target")
pd.DataFrame(data,columns=cols)
示例2:分析糖尿病数据集
这是回归数据集,有442个样本,有可能就有442个目标值。
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
iris = load_iris()
feature = iris.data
target = iris.targettarget.shape=(len(target), 1)
data = np.hstack([feature, target])
cols = iris.feature_names
cols.append("target")
pd.DataFrame(data,columns=cols)
4 sklearn获取现实世界数据集
(1)所有现实世界数据,通过网络才能下载后,默认保存的目录可以使用下面api获取。实际上就是保存到home目录
from sklearn import datasets
datasets.get_data_home() #查看数据集默认存放的位置
(2)下载时,有可能回为网络问题而出问题,要“小心”的解决网络问题,不可言…..
(3)第一次下载会保存的硬盘中,如果第二次下载,因为硬盘中已经保存有了,所以不会再次下载就直接加载成功了。
示例:获取20分类新闻数据
(1)使用函数: sklearn.datasets.fetch_20newsgroups(data_home,subset)
(2)函数参数说明:
(2.1) data_home
None
这是默认值,下载的文件路径为 “C:/Users/ADMIN/scikit_learn_data/20news-bydate_py3.pkz”
自定义路径
例如 “./src”, 下载的文件路径为“./20news-bydate_py3.pkz”
(2.2) subset
“train”,只下载训练集
“test”,只下载测试集
“all”, 下载的数据包含了训练集和测试集
(2.3) return_X_y,决定着返回值的情况
False,这是默认值
True,
(3) 函数返值说明:
当参数return_X_y值为False时, 函数返回Bunch对象,Bunch对象中有以下属性
*data:特征数据集, 长度为18846的列表list, 每一个元素就是一篇新闻内容, 共有18846篇
*target:目标数据集,长度为18846的数组ndarray, 第一个元素是一个整数,整数值为[0,20)
*target_names:目标描述,长度为20的list
*filenames:长度为18846的ndarray, 元素为字符串,代表新闻的数据位置的路径
当参数return_X_y值为True时,函数返回值为元组,元组长度为2, 第一个元素值为特征数据集,第二个元素值为目标数据集
代码
from sklearn.datasets import fetch_20newsgroups #这是一个20分类的数据
news = fetch_20newsgroups(data_home=None,subset='all')
print(len(news.data)) #18846
print(news.target.shape) #(18846,)
print(len(news.target_names)) #20
print(len(news.filenames)) #18846
5 本地csv数据
(1) 创建csv文件
方式1:打开计事本,写出如下数据,数据之间使用英文下的逗号, 保存文件后把后缀名改为csv
csv文件可以使用excel打开
, milage,Liters,Consumtime,target
40920,8.326976,0.953952,3
14488,7.153469,1.673904,2
26052,1.441871,0.805124,1
75136,13.147394,0.428964,1
方式2:创建excel 文件, 填写数据,以csv为后缀保存文件
(2) pandas加载csv
使用pandas的read_csv(“文件路径”)函数可以加载csv文件,得到的结果为数据的DataFrame形式
pd.read_csv("./src/ss.csv")
6 数据集的划分
"""
1. 复习不定长参数
一个"*" 把多个参数转为元组
两个"*" 把多个关键字参数转为字典
"""
def m(*a, **b):
print(a) #('hello', 123)
print(b) #{'name': '小王', 'age': 30, 'sex': '男'}
m("hello", 123, name="小王", age=30, sex="男")2. 复习列表值的解析
list = [11,22,33]
a, b, c = list # a=11 b=22 c=33
a, b = ["小王", 30] #a="小王" b=30
(1) 函数
sklearn.model_selection.train_test_split(*arrays,**options)
参数
(1) *array
这里用于接收1到多个"列表、numpy数组、稀疏矩阵或padas中的DataFrame"。
(2) **options, 重要的关键字参数有:
test_size 值为0.0到1.0的小数,表示划分后测试集占的比例
random_state 值为任意整数,表示随机种子,使用相同的随机种子对相同的数据集多次划分结果是相同的。否则多半不同
strxxxx 分层划分,填y
2 返回值说明
返回值为列表list, 列表长度与形参array接收到的参数数量相关联, 形参array接收到的是什么类型,list中对应被划分出来的两部分就是什么类型
(2)示例
列表数据集划分
因为随机种子都使用了相同的整数(22),所以划分的划分的情况是相同的。
from sklearn.model_selection import train_test_split
data1 = [1, 2, 3, 4, 5]
data2 = ["1a", "2a","3a", "4a", "5a"]
a, b = train_test_split(data1, test_size=0.4, random_state=22)
print(a, b) #[4, 1, 5] [2, 3]a, b = train_test_split(data2, test_size=0.4, random_state=22)
print(a, b) #['4a', '1a', '5a'] ['2a', '3a']a, b, c, d = train_test_split(data1, data2, test_size=0.4, random_state=22)
print(a,b,c,d) #['4a', '1a', '5a'] ['2a', '3a']
ndarray数据集划分
划分前和划分后的数据类型是相同的 data1为list,划分后的a、b也是list data2为ndarray,划分后的c、d也是ndarray
from sklearn.model_selection import train_test_split
import numpy as np
data1 = [1, 2, 3, 4, 5]
data2 = np.array(["1a", "2a","3a", "4a", "5a"])
a, b, c, d = train_test_split(data1, data2, test_size=0.4, random_state=22)
print(a, b, c, d) #[4, 1, 5] [2, 3] ['4a' '1a' '5a'] ['2a' '3a']
print(type(a), type(b), type(c), type(d)) #<class 'list'> <class 'list'> <class 'numpy.ndarray'> <class 'numpy.ndarray'>
二维数组数据集划分
train_test_split只划分第一维度,第二维度保持不变
from sklearn.model_selection import train_test_split
import numpy as np
data1 = np.arange(1, 16, 1)
data1.shape=(5,3)
print(data1)
a, b = train_test_split(data1, test_size=0.4, random_state=22)
print("a=\n", a)
print("b=\n", b)
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]
[13 14 15]]
a=
[[10 11 12]
[ 1 2 3]
[13 14 15]]
b=
[[4 5 6]
[7 8 9]]
DataFrame数据集划分
可以划分DataFrame, 划分后的两部分还是DataFrame
from sklearn.model_selection import train_test_split
import numpy as np
import pandas as pd
data1 = np.arange(1, 16, 1)
data1.shape=(5,3)
data1 = pd.DataFrame(data1, index=[1,2,3,4,5], columns=["one","two","three"])
print(data1)a, b = train_test_split(data1, test_size=0.4, random_state=22)
print("\n", a)
print("\n", b)
one two three
1 1 2 3
2 4 5 6
3 7 8 9
4 10 11 12
5 13 14 15one two three
4 10 11 12
1 1 2 3
5 13 14 15one two three
2 4 5 6
3 7 8 9
字典数据集划分
可以划分非稀疏矩阵
用于将字典列表转换为特征向量。这个转换器主要用于处理类别数据和数值数据的混合型数据集
1.对于类别特征DictVectorizer
会为每个不同的类别创建一个新的二进制特征,如果原始数据中的某个样本具有该类别,则对应的二进制特征值为1,否则为0。
2.对于数值特征保持不变,直接作为特征的一部分
这样,整个数据集就被转换成了一个适合机器学习算法使用的特征向量形式
from sklearn.feature_extraction import DictVectorizer
data = [{'city':'成都', 'age':30, 'temperature':20},
{'city':'重庆','age':33, 'temperature':60},
{'city':'北京', 'age':42, 'temperature':80},
{'city':'上海', 'age':22, 'temperature':70},
{'city':'成都', 'age':72, 'temperature':40},
]
transfer = DictVectorizer(sparse=True)
data_new = transfer.fit_transform(data)
print("data_new:\n", data_new)
x = data_new.toarray()
print(type(x))
print(x)
#(0,0)是矩阵的行列下标 30是值
data_new:
(0, 0) 30.0
(0, 3) 1.0
(0, 5) 20.0
(1, 0) 33.0
(1, 4) 1.0
(1, 5) 60.0
(2, 0) 42.0
(2, 2) 1.0
(2, 5) 80.0
(3, 0) 22.0
(3, 1) 1.0
(3, 5) 70.0
(4, 0) 72.0
(4, 3) 1.0
(4, 5) 40.0
<class 'numpy.ndarray'>
# 第一行中:30表示age的值 0表示上海 0表示北京 1表示成都 0表示重庆 20表示temperature#[age. 上海. 北京. 成都. 重庆. temperature.]其中上海北京成都重庆为二进制特征用0、1表示,[0. 0. 1. 0.]分别代表不是上海、不是北京、是成都、不是重庆
[[30. 0. 0. 1. 0. 20.]
[33. 0. 0. 0. 1. 60.]
[42. 0. 1. 0. 0. 80.]
[22. 1. 0. 0. 0. 70.]
[72. 0. 0. 1. 0. 40.]]
a, b = train_test_split(data_new, test_size=0.4, random_state=22)
print(a)
print("\n", b)
(0, 0) 22.0
(0, 1) 1.0
(0, 5) 70.0
(1, 0) 30.0
(1, 3) 1.0
(1, 5) 20.0
(2, 0) 72.0
(2, 3) 1.0
(2, 5) 40.0(0, 0) 33.0
(0, 4) 1.0
(0, 5) 60.0
(1, 0) 42.0
(1, 2) 1.0
(1, 5) 80.0
#data_new.toarray()是ndarray
a, b = train_test_split(data_new.toarray(), test_size=0.4, random_state=22)
print(a)
print("\n", b)
[[22. 1. 0. 0. 0. 70.]
[30. 0. 0. 1. 0. 20.]
[72. 0. 0. 1. 0. 40.]][[33. 0. 0. 0. 1. 60.]
[42. 0. 1. 0. 0. 80.]]
鸢尾花数据集划分
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
list = train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)
#x_train训练特征数据集,x_test测试特征数据集, y_train训练目标数据集,y_test测试目标数据集,
x_train, x_test, y_train, y_test = list
#打印结果为: (120, 4) (30, 4) (120,) (30,)
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)
现实世界数据集划分
from sklearn.datasets import fetch_20newsgroups
from sklearn.model_selection import train_test_split
import numpy as np
news = fetch_20newsgroups(data_home=None, subset='all')
list = train_test_split(news.data, news.target,test_size=0.2, random_state=22)
# """
# 返回值是一个list:其中有4个值,分别为训练集特征、测试集特征、训练集目标、测试集目标
# 与iris相同点在于x_train和x_test是列表,而iris是
# """
x_train, x_test, y_train, y_test = list
#打印结果为: 15076 3770 (15076,) (3770,)
print(len(x_train), len(x_test), y_train.shape, y_test.shape)
四 特征工程
1 特征工程概念
特征工程:就是对特征进行相关的处理
一般使用pandas来进行数据清洗和数据处理、使用sklearn来进行特征工程
特征工程是将任意数据(如文本或图像)转换为可用于机器学习的数字特征,比如:字典特征提取(特征离散化)、文本特征提取、图像特征提取。
特征工程步骤为:
-
特征提取, 如果不是像dataframe那样的数据,要进行特征提取,比如字典特征提取,文本特征提取
-
无量纲化(预处理)
-
归一化
-
标准化
-
-
降维
-
底方差过滤特征选择
-
主成分分析-PCA降维
-
2 特征工程API
-
实例化转换器对象,转换器类有很多,都是Transformer的子类, 常用的子类有:
DictVectorizer 字典特征提取
CountVectorizer 文本特征提取
TfidfVectorizer TF-IDF文本特征词的重要程度特征提取
MinMaxScaler 归一化
StandardScaler 标准化
VarianceThreshold 底方差过滤降维
PCA 主成分分析降维
转换器对象调用fit_transform()进行转换, 其中fit用于计算数据,transform进行最终转换
fit_transform()可以使用fit()和transform()代替
fit()使用训练集数据获得训练集数据的训练模型参数(如均值、方差等),transform()的作用是应用fit()训练的参数对输入数据进行转换
data_new = transfer.fit_transform(data)
可写成
transfer.fit(data)
data_new = transfer.transform(data)
3 DictVectorizer 字典列表特征提取
稀疏矩阵
稀疏矩阵是指一个矩阵中大部分元素为零,只有少数元素是非零的矩阵。在数学和计算机科学中,当一个矩阵的非零元素数量远小于总的元素数量,且非零元素分布没有明显的规律时,这样的矩阵就被认为是稀疏矩阵。例如,在一个1000 x 1000的矩阵中,如果只有1000个非零元素,那么这个矩阵就是稀疏的。
由于稀疏矩阵中零元素非常多,存储和处理稀疏矩阵时,通常会采用特殊的存储格式,以节省内存空间并提高计算效率。
三元组表 (Coordinate List, COO):三元组表就是一种稀疏矩阵类型数据,存储非零元素的行索引、列索引和值:
(行,列) 数据
(0,0) 10
(0,1) 20
(2,0) 90
(2,20) 8
(8,0) 70
表示除了列出的有值, 其余全是0
非稀疏矩阵(稠密矩阵)
非稀疏矩阵,或称稠密矩阵,是指矩阵中非零元素的数量与总元素数量相比接近或相等,也就是说矩阵中的大部分元素都是非零的。在这种情况下,矩阵的存储通常采用标准的二维数组形式,因为非零元素密集分布,不需要特殊的压缩或优化存储策略。
-
存储:稀疏矩阵使用特定的存储格式来节省空间,而稠密矩阵使用常规的数组存储所有元素,无论其是否为零。
-
计算:稀疏矩阵在进行计算时可以利用零元素的特性跳过不必要的计算,从而提高效率。而稠密矩阵在计算时需要处理所有元素,包括零元素。
-
应用领域:稀疏矩阵常见于大规模数据分析、图形学、自然语言处理、机器学习等领域,而稠密矩阵在数学计算、线性代数等通用计算领域更为常见。
在实际应用中,选择使用稀疏矩阵还是稠密矩阵取决于具体的问题场景和数据特性。
(1) api
-
创建转换器对象:
sklearn.feature_extraction.DictVectorizer(sparse=True)
参数:
sparse=True返回类型为csr_matrix的稀疏矩阵
sparse=False表示返回的是数组,数组可以调用.toarray()方法将稀疏矩阵转换为数组
-
转换器对象:
转换器对象调用fit_transform(data)函数,参数data为一维字典数组或一维字典列表,返回转化后的矩阵或数组
转换器对象get_feature_names_out()方法获取特征名
(2)示例1 提取为稀疏矩阵对应的数组
from sklearn.feature_extraction import DictVectorizer
data = [{'city':'成都', 'age':30, 'temperature':200}, {'city':'重庆','age':33, 'temperature':60}, {'city':'北京', 'age':42, 'temperature':80}]
#创建DictVectorizer对象
transfer = DictVectorizer(sparse=False)
data_new = transfer.fit_transform(data)
# data_new的类型为ndarray
#特征数据
print("data_new:\n", data_new)
#特征名字
print("特征名字:\n", transfer.get_feature_names_out())
data_new:
[[ 30. 0. 1. 0. 200.]
[ 33. 0. 0. 1. 60.]
[ 42. 1. 0. 0. 80.]]
特征名字:
['age' 'city=北京' 'city=成都' 'city=重庆' 'temperature']
import pandas
pandas.DataFrame(data_new, columns=transfer.get_feature_names_out())
(3)示例2 提取为稀疏矩阵
from sklearn.feature_extraction import DictVectorizer
data = [{'city':'成都', 'age':30, 'temperature':200}, {'city':'重庆','age':33, 'temperature':60}, {'city':'北京', 'age':42, 'temperature':80}]
#创建DictVectorizer对象
transfer = DictVectorizer(sparse=True)
data_new = transfer.fit_transform(data)
#data_new的类型为<class 'scipy.sparse._csr.csr_matrix'>
print("data_new:\n", data_new)
#得到特征
print("特征名字:\n", transfer.get_feature_names_out())
其中(row,col)数据中的col表示特征, 本示例中0表示 ‘age’, 1表示‘city=北京’,……
data_new:
(0, 0) 30.0
(0, 2) 1.0
(0, 4) 200.0
(1, 0) 33.0
(1, 3) 1.0
(1, 4) 60.0
(2, 0) 42.0
(2, 1) 1.0
(2, 4) 80.0
特征名字:
['age' 'city=北京' 'city=成都' 'city=重庆' 'temperature']
(4)稀疏矩阵转为数组
稀疏矩阵对象调用toarray()函数, 得到类型为ndarray的二维稀疏矩阵
4 CountVectorizer 文本特征提取
(1)API
sklearn.feature_extraction.text.CountVectorizer
构造函数关键字参数stop_words,值为list,表示词的黑名单(不提取的词)
fit_transform函数的返回值为稀疏矩阵
(2) 英文文本提取
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
data=["stu is well, stu is great", "You like stu"]
#创建转换器对象, you和is不提取
transfer = CountVectorizer(stop_words=["you","is"])
#进行提取,得到稀疏矩阵
data_new = transfer.fit_transform(data)
print(data_new)import pandas
pandas.DataFrame(data_new.toarray(),
index=["第一个句子","第二个句子"],
columns=transfer.get_feature_names_out())
(3) 中文文本提取
a.中文文本不像英文文本,中文文本文字之间没有空格,所以要先分词,一般使用jieba分词.
b.下载jieba组件, (不要使用conda)
pip install jieba
c.jieba的基础
import jieba
data = "在如今的互联网世界,正能量正成为澎湃时代的大流量"
data = jieba.cut(data)
data = list(data)
print(data) #['在', '如今', '的', '互联网', '世界', ',', '正', '能量', '正', '成为', '澎湃', '时代', '的', '大', '流量']
data = " ".join(data)
print(data) #"在 如今 的 互联网 世界 , 正 能量 正 成为 澎湃 时代 的 大 流量"
使用jieba封装一个函数,功能是把汉语字符串中进行分词(会忽略长度小于等于1的词语,因为它们往往缺乏语义信息,不能很好地表达文本的特征)
import jieba
def cut(text):
return " ".join(list(jieba.cut(text)))
data = "在如今的互联网世界,正能量正成为澎湃时代的大流量"
data = cut(data)
print(data) #"在 如今 的 互联网 世界 , 正 能量 正 成为 澎湃 时代 的 大 流量"
完整终合示例
import jieba
from sklearn.feature_extraction.text import CountVectorizerdef cut(text):
return " ".join(list(jieba.cut(text)))data = ["教育学会会长期间坚定支持民办教育事业!","热忱关心、扶持民办学校发展","事业做出重大贡献!"]
data_new = [cut(v) for v in data]transfer = CountVectorizer(stop_words=['期间', '做出'])
data_final = transfer.fit_transform(data_new)print(data_final.toarray())#把非稀疏矩阵转变为稀疏矩阵
print(transfer.get_feature_names_out())#import pandas as pd
pd.DataFrame(data_final.toarray(), columns=transfer.get_feature_names_out())
import pandas
mylist = []
for i in range(len(data)):
print("第"+str(i)+"名")
mylist.append("第"+str(i)+"句")
pandas.DataFrame(data_final.toarray(), index=mylist, columns=transfer.get_feature_names_out())
5 TfidfVectorizer TF-IDF文本特征词的重要程度特征提取
(1) 算法A
词频(Term Frequency, TF), 表示一个词在当前篇文章中的重要性
逆文档频率(Inverse Document Frequency, IDF), 反映了词在整个文档集合中的稀有程度
(2) API
sklearn.feature_extraction.text.TfidfVectorizer()
构造函数关键字参数stop_words,表示词特征黑名单
fit_transform函数的返回值为稀疏矩阵
(3) 示例
代码与CountVectorizer的示例基本相同,仅仅把CountVectorizer改为TfidfVectorizer即可
示例中data是一个字符串list, list中的第一个元素就代表一篇文章.
import jieba
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizerdef cut_words(text):
return " ".join(list(jieba.cut(text)))data = ["教育学会会长期间,坚定支持民办教育事业!", "扶持民办,学校发展事业","事业做出重大贡献!"]
data_new = [cut_words(v) for v in data]transfer = TfidfVectorizer(stop_words=['期间', '做出',"重大贡献"])
data_final = transfer.fit_transform(data_new)pd.DataFrame(data_final.toarray(), columns=transfer.get_feature_names_out())
from sklearn.feature_extraction.text import CountVectorizer
transfer = CountVectorizer(stop_words=['期间', '做出',"重大贡献"])
data_final = transfer.fit_transform(data_new)pd.DataFrame(data_final.toarray(), columns=transfer.get_feature_names_out())
补充:在sklearn库中 TF-IDF算法做了一些细节的优化
词频 (TF)
词频是指一个词在文档中出现的频率。通常有两种计算方法:
-
原始词频:一个词在文档中出现的次数除以文档中总的词数。
-
平滑后的词频:为了防止高频词主导向量空间,有时会对词频进行平滑处理,例如使用
1 + log(TF)
。 -
在 TfidfVectorizer 中,TF 默认是:直接使用一个词在文档中出现的次数也就是CountVectorizer的结果
逆文档频率 (IDF)
逆文档频率衡量一个词的普遍重要性。如果一个词在许多文档中都出现,那么它的重要性就会降低。
IDF 的计算公式是:
$$IDF(t)=\log(\dfrac{总文档数}{包含词t的文档数+1})$$
在 TfidfVectorizer 中,IDF 的默认计算公式是:
$$IDF(t)=\log(\dfrac{总文档数+1}{包含词t的文档数+1})+1$$
在 TfidfVectorizer 中还会进行归一化处理(采用的L2归一化)
L2归一化
$$x_1归一化后的数据=\dfrac{x_1}{\sqrt{x_1^2+x_2^2+...x_n^2}}$$
x可以选择是行或者列的数据
from sklearn.feature_extraction.text import CountVectorizer,TfidfVectorizer
from sklearn.preprocessing import normalize
from sklearn.preprocessing import StandardScaler
import jieba
import pandas as pd
import numpy as np
def my_cut(text):
return " ".join(jieba.cut(text))
data=["教育学会会长期间,坚定支持民办教育事业!", "扶持民办,学校发展事业","事业做出重大贡献!"]
data=[my_cut(i) for i in data]
print(data)
# print("词频",CountVectorizer().fit_transform(data).toarray())
transfer=TfidfVectorizer()
res=transfer.fit_transform(data)
print(pd.DataFrame(res.toarray(),columns=transfer.get_feature_names_out()))
# 手动实现tfidf向量(跟上面的api实现出一样的效果)
def tfidf(data):
# 计算词频
count = CountVectorizer().fit_transform(data).toarray()
print("count",count)
print(np.sum(count != 0, axis=0))
# 计算IDF,并采用平滑处理
idf = np.log((len(data) + 1) / (1 + np.sum(count != 0, axis=0))) + 1
# 计算TF-IDF
tf_idf = count * idf
# L2标准化
tf_idf_normalized = normalize(tf_idf, norm='l2', axis=1)#axis=0是列 axis=1是行
return tf_idf,tf_idf_normalized
tf_idf,tf_idf_normalized=tfidf(data)
print(pd.DataFrame(tf_idf,columns=transfer.get_feature_names_out()))
print(pd.DataFrame(tf_idf_normalized,columns=transfer.get_feature_names_out()))
6 无量纲化-预处理
无量纲,即没有单位的数据
无量纲化包括"归一化"和"标准化", 为什么要进行无量纲化呢?
这是一个男士的数据表:
假设算法中需要求它们之间的欧式距离, 这里以编号1和编号2为示例:
$L = \sqrt{(1.75-1.5)^2+(15000-16000)^2+(120-140)^2}$
从计算上来看, 发现身高对计算结果没有什么影响, 基本主要由收入来决定了,但是现实生活中,身高是比较重要的判断标准. 所以需要无量纲化.
(1) MinMaxScaler 归一化
通过对原始数据进行变换把数据映射到指定区间(默认为0-1)
<1>归一化公式:
这里的 𝑥min 和 𝑥max 分别是每种特征中的最小值和最大值,而 𝑥是当前特征值,𝑥scaled 是归一化后的特征值。
若要缩放到其他区间,可以使用公式:x=x*(max-min)+min;
手算过程:
<2>归一化API
sklearn.preprocessing.MinMaxScaler(feature_range)
参数:feature_range=(0,1) 归一化后的值域,可以自己设定
fit_transform函数归一化的原始数据类型可以是list、DataFrame和ndarray, 不可以是稀疏矩阵
fit_transform函数的返回值为ndarray
<3>归一化示例
示例1:原始数据类型为list
from sklearn.preprocessing import MinMaxScaler
data=[[12,22,4],[22,23,1],[11,23,9]]
#feature_range=(0, 1)表示归一化后的值域,可以自己设定
transfer = MinMaxScaler(feature_range=(0, 1))
#data_new的类型为<class 'numpy.ndarray'>
data_new = transfer.fit_transform(data)
print(data_new)
[[0.09090909 0. 0.375 ]
[1. 1. 0. ]
[0. 1. 1. ]]
示例2:原始数据类型为DataFrame
from sklearn.preprocessing import MinMaxScaler
import pandas as pd;
data=[[12,22,4],[22,23,1],[11,23,9]]
data = pd.DataFrame(data=data, index=["一","二","三"], columns=["一列","二列","三列"])
transfer = MinMaxScaler(feature_range=(0, 1))
data_new = transfer.fit_transform(data)
print(data_new)
示例3:原始数据类型为 ndarray
from sklearn.feature_extraction import DictVectorizer
from sklearn.preprocessing import MinMaxScalerdata = [{'city':'成都', 'age':30, 'temperature':200}, {'city':'重庆','age':33, 'temperature':60}, {'city':'北京', 'age':42, 'temperature':80}]
transfer = DictVectorizer(sparse=False)
data = transfer.fit_transform(data) #data类型为ndarray
print(data)transfer = MinMaxScaler(feature_range=(0, 1))
data = transfer.fit_transform(data)
print(data)
<4>缺点
最大值和最小值容易受到异常点影响,所以鲁棒性较差。所以常使用标准化的无量钢化
(2)normalize归一化
API
from sklearn.preprocessing import normalize
normalize(data, norm='l2', axis=1)
#data是要归一化的数据
#norm是使用那种归一化:"l1" "l2" "max
#axis=0是列 axis=1是行
<1> L1归一化
绝对值相加作为分母,特征值作为分子
<2> L2归一化
平方相加作为分母,特征值作为分子
<3> max归一化
max作为分母,特征值作为分子
(3)StandardScaler 标准化
在机器学习中,标准化是一种数据预处理技术,也称为数据归一化或特征缩放。它的目的是将不同特征的数值范围缩放到统一的标准范围,以便更好地适应一些机器学习算法,特别是那些对输入数据的尺度敏感的算法。
<1>标准化公式
最常见的标准化方法是Z-score标准化,也称为零均值标准化。它通过对每个特征的值减去其均值,再除以其标准差,将数据转换为均值为0,标准差为1的分布。这可以通过以下公式计算:
其中,z是转换后的数值,x是原始数据的值,μ是该特征的均值,σ是该特征的 标准差
<2> 标准化 API
sklearn.preprocessing.StandardScale
与MinMaxScaler一样,原始数据类型可以是list、DataFrame和ndarray
fit_transform函数的返回值为ndarray, 归一化后得到的数据类型都是ndarray
from sklearn.preprocessing import StandardScaler
#不能加参数feature_range=(0, 1)
transfer = StandardScaler()
data_new = transfer.fit_transform(data) #data_new的类型为ndarray
<3>标准化示例
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
# 1、获取数据
df_data = pd.read_csv("src/dating.txt")
print(type(df_data)) #<class 'pandas.core.frame.DataFrame'>
print(df_data.shape) #(1000, 4)# 2、实例化一个转换器类
transfer = StandardScaler()# 3、调用fit_transform
new_data = transfer.fit_transform(df_data) #把DateFrame数据进行归一化
print("DateFrame数据被归一化后:\n", new_data[0:5])nd_data = df_data.values #把DateFrame转为ndarray
new_data = transfer.fit_transform(nd_data) #把ndarray数据进行归一化
print("ndarray数据被归一化后:\n", new_data[0:5])nd_data = df_data.values.tolist() #把DateFrame转为list
new_data = transfer.fit_transform(nd_data) #把ndarray数据进行归一化
print("list数据被归一化后:\n", new_data[0:5])
<class 'pandas.core.frame.DataFrame'>
(1000, 4)
DateFrame数据被归一化后:
[[ 0.33193158 0.41660188 0.24523407 1.24115502]
[-0.87247784 0.13992897 1.69385734 0.01834219]
[-0.34554872 -1.20667094 -0.05422437 -1.20447063]
[ 1.89102937 1.55309196 -0.81110001 -1.20447063]
[ 0.2145527 -1.15293589 -1.40400471 -1.20447063]]
ndarray数据被归一化后:
[[ 0.33193158 0.41660188 0.24523407 1.24115502]
[-0.87247784 0.13992897 1.69385734 0.01834219]
[-0.34554872 -1.20667094 -0.05422437 -1.20447063]
[ 1.89102937 1.55309196 -0.81110001 -1.20447063]
[ 0.2145527 -1.15293589 -1.40400471 -1.20447063]]
list数据被归一化后:
[[ 0.33193158 0.41660188 0.24523407 1.24115502]
[-0.87247784 0.13992897 1.69385734 0.01834219]
[-0.34554872 -1.20667094 -0.05422437 -1.20447063]
[ 1.89102937 1.55309196 -0.81110001 -1.20447063]
[ 0.2145527 -1.15293589 -1.40400471 -1.20447063]]
自己实现标准化来测试
#数据
data=np.array([[5],
[20],
[40],
[80],
[100]])
#API实现标准化
data_news=scaler.fit_transform(data)
print("API实现:\n",data_news)#标准化自己实现
mu=np.mean(data)
sum=0
for i in data:
sum+=((i[0]-mu)**2)
d=np.sqrt(sum/(len(data)))
print("自己实现:\n",(data[3]-mu)/d)
<4> 注意点
在数据预处理中,特别是使用如StandardScaler
这样的数据转换器时,fit
、fit_transform
和transform
这三个方法的使用是至关重要的,它们各自有不同的作用:
-
fit:
-
这个方法用来计算数据的统计信息,比如均值和标准差(在
StandardScaler
的情况下)。这些统计信息随后会被用于数据的标准化。 -
你应当仅在训练集上使用
fit
方法。
-
-
fit_transform:
-
这个方法相当于先调用
fit
再调用transform
,但是它在内部执行得更高效。 -
它同样应当仅在训练集上使用,它会计算训练集的统计信息并立即应用到该训练集上。
-
-
transform:
-
这个方法使用已经通过
fit
方法计算出的统计信息来转换数据。 -
它可以应用于任何数据集,包括训练集、验证集或测试集,但是应用时使用的统计信息必须来自于训练集。
-
当你在预处理数据时,首先需要在训练集X_train
上使用fit_transform
,这样做可以一次性完成统计信息的计算和数据的标准化。这是因为我们需要确保模型是基于训练数据的统计信息进行学习的,而不是整个数据集的统计信息。
一旦scaler
对象在X_train
上被fit
,它就已经知道了如何将数据标准化。这时,对于测试集X_test
,我们只需要使用transform
方法,因为我们不希望在测试集上重新计算任何统计信息,也不希望测试集的信息影响到训练过程。如果我们对X_test
也使用fit_transform
,测试集的信息就可能会影响到训练过程。
总结来说:我们常常是先fit_transform(x_train)然后再transform(x_text)
7 特征降维
实际数据中,有时候特征很多,会增加计算量,降维就是去掉一些特征,或者转化多个特征为少量个特征
特征降维其目的:是减少数据集的维度,同时尽可能保留数据的重要信息。
特征降维的好处:
减少计算成本:在高维空间中处理数据可能非常耗时且计算密集。降维可以简化模型,降低训练时间和资源需求。
去除噪声:高维数据可能包含许多无关或冗余特征,这些特征可能引入噪声并导致过拟合。降维可以帮助去除这些不必要的特征。
特征降维的方式:
-
特征选择
-
从原始特征集中挑选出最相关的特征
-
-
主成份分析(PCA)
-
主成分分析就是把之前的特征通过一系列数学计算,形成新的特征,新的特征数量会小于之前特征数量
-
1 .特征选择
(a) VarianceThreshold 低方差过滤特征选择
-
Filter(过滤式): 主要探究特征本身特点, 特征与特征、特征与目标 值之间关联
-
方差选择法: 低方差特征过滤
如果一个特征的方差很小,说明这个特征的值在样本中几乎相同或变化不大,包含的信息量很少,模型很难通过该特征区分不同的对象,比如区分甜瓜子和咸瓜子还是蒜香瓜子,如果有一个特征是长度,这个特征相差不大可以去掉。
-
计算方差:对于每个特征,计算其在训练集中的方差(每个样本值与均值之差的平方,在求平均)。
-
设定阈值:选择一个方差阈值,任何低于这个阈值的特征都将被视为低方差特征。
-
过滤特征:移除所有方差低于设定阈值的特征
-
-
创建对象,准备把方差为等于小于2的去掉,threshold的缺省值为2.0
sklearn.feature_selection.VarianceThreshold(threshold=2.0)把x中低方差特征去掉, x的类型可以是DataFrame、ndarray和list
VananceThreshold.fit_transform(x)
fit_transform函数的返回值为ndarray
from sklearn.feature_selection import VarianceThreshold
import pandas as pd
def variance_demo():
# 1、获取数据,data是一个DataFrame,可以是读取的csv文件
data=pd.DataFrame([[10,1],[11,3],[11,1],[11,5],[11,9],[11,3],[11,2],[11,6]])
print("data:\n", data)
# 2、实例化一个转换器类
transfer = VarianceThreshold(threshold=1)#0.1阈值
# 3、调用fit_transform
data_new = transfer.fit_transform(data)
print("data_new:\n",data_new)
return None
variance_demo()
(b) 根据相关系数的特征选择
<1>理论
正相关性(Positive Correlation)是指两个变量之间的一种统计关系,其中一个变量的增加通常伴随着另一个变量的增加,反之亦然。在正相关的关系中,两个变量的变化趋势是同向的。当我们说两个变量正相关时,意味着:
-
如果第一个变量增加,第二个变量也有很大的概率会增加。
-
同样,如果第一个变量减少,第二个变量也很可能会减少。
正相关性并不意味着一个变量的变化直接引起了另一个变量的变化,它仅仅指出了两个变量之间存在的一种统计上的关联性。这种关联性可以是因果关系,也可以是由第三个未观察到的变量引起的,或者是纯属巧合。
在数学上,正相关性通常用正值的相关系数来表示,这个值介于0和1之间。当相关系数等于1时,表示两个变量之间存在完美的正相关关系,即一个变量的值可以完全由另一个变量的值预测。
举个例子,假设我们观察到在一定范围内,一个人的身高与其体重呈正相关,这意味着在一般情况下,身高较高的人体重也会较重。但这并不意味着身高直接导致体重增加,而是可能由于营养、遗传、生活方式等因素共同作用的结果。
负相关性(Negative Correlation)与正相关性刚好相反,但是也说明相关,比如运动频率和BMI体重指数程负相关
不相关指两者的相关性很小,一个变量变化不会引起另外的变量变化,只是没有线性关系. 比如饭量和智商
皮尔逊相关系数(Pearson correlation coefficient)是一种度量两个变量之间线性相关性的统计量。它提供了两个变量间关系的方向(正相关或负相关)和强度的信息。皮尔逊相关系数的取值范围是 [−1,1],其中:
-
$\rho=1$ 表示完全正相关,即随着一个变量的增加,另一个变量也线性增加。
-
$\rho=-1$ 表示完全负相关,即随着一个变量的增加,另一个变量线性减少。
-
$\rho=0$ 表示两个变量之间不存在线性关系。
相关系数$\rho$的绝对值为0-1之间,绝对值越大,表示越相关,当两特征完全相关时,两特征的值表示的向量是
在同一条直线上,当两特征的相关系数绝对值很小时,两特征值表示的向量接近在同一条直线上。当相关系值为负数时,表示负相关
<2>皮尔逊相关系数:pearsonr相关系数计算公式, 该公式出自于概率论
对于两组数据 𝑋={𝑥1,𝑥2,...,𝑥𝑛} 和 𝑌={𝑦1,𝑦2,...,𝑦𝑛},皮尔逊相关系数可以用以下公式计算:
$\rho=\frac{\operatorname{Cos}(x, y)}{\sqrt{D x} \cdot \sqrt{D y}}=\frac{E[(x-E x)(y-E y)]}{\sqrt{D x} \cdot \sqrt{D y}}=\frac{\sum{i=1}^{n}(x-\tilde{x})(y-\bar{y}) /(n-1)}{\sqrt{\sum{i=1}^{n}(x-\bar{x})^{2} /(n-1)} \cdot \sqrt{\sum{i=1}^{n}(y-\bar{y})^{2} /(n-1)}}$
$\bar{x}$和 $\bar{y}$ 分别是𝑋和𝑌的平均值
|ρ|<0.4为低度相关; 0.4<=|ρ|<0.7为显著相关; 0.7<=|ρ|<1为高度相关
<3>api:
scipy.stats.personr(x, y) 计算两特征之间的相关性
返回对象有两个属性:
statistic皮尔逊相关系数[-1,1]
pvalue零假设(了解),统计上评估两个变量之间的相关性,越小越相关
<4>示例:
from scipy.stats import pearsonr
def association_demo():
# 1、获取数据
data = pd.read_csv("src/factor_returns.csv")
data = data.iloc[:, 1:-2]
# 计算某两个变量之间的相关系数
r1 = pearsonr(data["pe_ratio"], data["pb_ratio"])
print(r1.statistic) #-0.0043893227799362555 相关性, 负数表示负相关,正数表示正相关
print(r1.pvalue) #0.8327205496590723 相关性,越小越相关
r2 = pearsonr(data['revenue'], data['total_expense'])
print(r2) #PearsonRResult(statistic=0.9958450413136111, pvalue=0.0)
return None
association_demo()
开发中一般不使用求相关系数的方法,一般使用主成分分析,因为主成分分样过程中就包括了求相关系数了。
2.主成份分析(PCA)
PCA的核心目标是从原始特征空间中找到一个新的坐标系统,使得数据在新坐标轴上的投影能够最大程度地保留数据的方差,同时减少数据的维度。
(a) 原理
$x_0$投影到L的大小为$x_0*cos \alpha$
$y_0$投影到L的大小为$y_0*sin\alpha$
使用$(x_0,y_0)$表示一个点, 表明该点有两个特征, 而映射到L上有一个特征就可以表示这个点了。这就达到了降维的功能 。
投影到L上的值就是降维后保留的信息,投影到与L垂直的轴上的值就是丢失的信息。保留信息/原始信息=信息保留的比例
下图中红线上点与点的距离是最大的,所以在红色线上点的方差最大,粉红线上的刚好相反.
所以红色线上点来表示之前点的信息损失是最小的。
(b) 步骤
-
得到矩阵
-
用矩阵P对原始数据进行线性变换,得到新的数据矩阵Z,每一列就是一个主成分, 如下图就是把10维降成了2维,得到了两个主成分
-
根据主成分的方差等,确定最终保留的主成分个数, 方差大的要留下。一个特征的多个样本的值如果都相同,则方差为0, 则说明该特征值不能区别样本,所以该特征没有用。
比如下图的二维数据要降为一维数据,图形法是把所在数据在二维坐标中以点的形式标出,然后给出一条直线,让所有点垂直映射到直线上,该直线有很多,只有点到线的距离之和最小的线才能让之前信息损失最小。
这样之前所有的二维表示的点就全部变成一条直线上的点,从二维降成了一维。
上图是一个从二维降到一维的示例:的原始数据为
降维后新的数据为
3.api
-
from sklearn.decomposition import PCA
-
PCA(n_components=None)
-
主成分分析
-
n_components:
-
实参为小数时:表示降维后保留百分之多少的信息
-
实参为整数时:表示减少到多少特征
-
-
(3)示例-n_components为小数
from sklearn.decomposition import PCA
def pca_demo():
data = [[2,8,4,5],
[6,3,0,8],
[5,4,9,1]]
# 1、实例化一个转换器类, 降维后还要保留原始数据0.95%的信息, 最后的结果中发现由4个特征降维成2个特征了
transfer = PCA(n_components=0.95)
# 2、调用fit_transform
data_new = transfer.fit_transform(data)
print("data_new:\n", data_new)
return None
pca_demo()
data_new:
[[-3.13587302e-16 3.82970843e+00]
[-5.74456265e+00 -1.91485422e+00]
[ 5.74456265e+00 -1.91485422e+00]]
(4)示例-n_components为整数
from sklearn.decomposition import PCA
def pca_demo():
data = [[2,8,4,5], [6,3,0,8], [5,4,9,1]]
# 1、实例化一个转换器类, 降维到只有3个特征
transfer = PCA(n_components=3)
# 2、调用fit_transform
data_new = transfer.fit_transform(data)
print("data_new:\n", data_new)
return None
pca_demo()
data_new:
[[-3.13587302e-16 3.82970843e+00 4.59544715e-16]
[-5.74456265e+00 -1.91485422e+00 4.59544715e-16]
[ 5.74456265e+00 -1.91485422e+00 4.59544715e-16]]
五 sklearn机器学习概述
获取数据、数据处理、特征工程后,就可以交给预估器进行机器学习,流程和常用API如下。
1.实例化预估器(估计器)对象(estimator), 预估器对象很多,都是estimator的子类
(1)用于分类的预估器
sklearn.neighbors.KNeighborsClassifier k-近邻
sklearn.naive_bayes.MultinomialNB 贝叶斯
sklearn.linear_model.LogisticRegressioon 逻辑回归
sklearn.tree.DecisionTreeClassifier 决策树
sklearn.ensemble.RandomForestClassifier 随机森林
(2)用于回归的预估器
sklearn.linear_model.LinearRegression线性回归
sklearn.linear_model.Ridge岭回归
(3)用于无监督学习的预估器
sklearn.cluster.KMeans 聚类
2.进行训练,训练结束后生成模型
estimator.fit(x_train, y_train)
3.模型评估
(1)方式1,直接对比
y_predict = estimator.predict(x_test)
y_test == y_predict
(2)方式2, 计算准确率
accuracy = estimator.score(x_test, y_test)
4.使用模型(预测)
y_predict = estimator.predict(x_true)
六 KNN算法-分类
1 样本距离判断
明可夫斯基距离
欧式距离,明可夫斯基距离的特殊情况
曼哈顿距离,明可夫斯基距离的特殊情况
两个样本的距离公式可以通过如下公式进行计算,又称为欧式距离。
(1)欧式距离
(2)曼哈顿距离
(3)其他距离 [了解就行]
1. Lp范数家族
-
闵可夫斯基距离(Minkowski Distance)
公式:D(x,y)=(∑i=1n∣xi−yi∣p)1/pD(x,y)=(∑i=1n∣xi−yi∣p)1/p- p=1p=1 时为曼哈顿距离,p=2p=2 时为欧式距离,p→∞p→∞ 时为切比雪夫距离。
-
切比雪夫距离(Chebyshev Distance)
公式:D(x,y)=maxi∣xi−yi∣D(x,y)=maxi∣xi−yi∣
场景:棋盘格移动(如国际象棋)、图像处理中的像素差异。
2. 方向相关距离
-
余弦相似度(Cosine Similarity)
公式:cos(θ)=x⋅y∥x∥∥y∥cos(θ)=∥x∥∥y∥x⋅y
场景:文本相似度(如TF-IDF向量)、推荐系统(忽略向量长度,关注方向)。 -
马氏距离(Mahalanobis Distance)
公式:D(x,y)=(x−y)TΣ−1(x−y)D(x,y)=(x−y)TΣ−1(x−y)(ΣΣ为协方差矩阵)
场景:处理尺度不同且特征相关的高维数据(如异常检测)。
3. 集合或分类数据距离
-
汉明距离(Hamming Distance)
公式:两个等长字符串对应位置不同的字符数。
场景:纠错编码(如CRC)、DNA序列比对。 -
杰卡德距离(Jaccard Distance)
公式:D=1−∣A∩B∣∣A∪B∣D=1−∣A∪B∣∣A∩B∣
场景:集合相似性(如用户兴趣比较)、文档去重。
4. 序列或结构化数据距离
-
编辑距离(Levenshtein Distance)
公式:将一个字符串转换为另一个所需的最小单字符编辑(插入、删除、替换)次数。
场景:自然语言处理(拼写纠错)、生物信息学(基因序列对齐)。 -
动态时间规整(DTW, Dynamic Time Warping)
场景:时间序列对齐(如语音识别、传感器数据匹配)。
5. 概率分布距离
-
KL散度(Kullback-Leibler Divergence)
公式:DKL(P∥Q)=∑P(x)logP(x)Q(x)DKL(P∥Q)=∑P(x)logQ(x)P(x)
场景:衡量两个概率分布的差异(如变分推断、生成模型)。 -
巴塔恰里亚距离(Bhattacharyya Distance)
公式:DB=−ln∑P(x)Q(x)DB=−ln∑P(x)Q(x)
场景:图像识别、分类任务中的分布相似性。
6. 其他特殊场景距离
-
卡方距离(Chi-Square Distance)
公式:D=∑(xi−yi)2xi+yiD=∑xi+yi(xi−yi)2
场景:直方图比较(图像检索)、统计检验。 -
标准化欧式距离(Standardized Euclidean)
公式:考虑各维度方差,D=∑(xi−yi)2σi2D=∑σi2(xi−yi)2
场景:特征尺度差异大的数据。
2 KNN 算法原理
K-近邻算法(K-Nearest Neighbors,简称KNN),根据K个邻居样本的类别来判断当前样本的类别;
如果一个样本在特征空间中的k个最相似(最邻近)样本中的大多数属于某个类别,则该类本也属于这个类别
比如: 有10000个样本,选出7个到样本A的距离最近的,然后这7个样本中假设:类别1有2个,类别2有3个,类别3有2个.那么就认为A样本属于类别2,因为它的7个邻居中 类别2最多(近朱者赤近墨者黑)
4. 举例
使用KNN算法预测《唐人街探案》电影属于哪种类型?分别计算每个电影和预测电影的距离然后求解:
3 KNN缺点
对于大规模数据集,计算量大,因为需要计算测试样本与所有训练样本的距离。
对于高维数据,距离度量可能变得不那么有意义,这就是所谓的“维度灾难”
需要选择合适的k值和距离度量,这可能需要一些实验和调整
4 API
class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, algorithm='auto')
参数:
(1)n_neighbors:
int, default=5, 默认情况下用于kneighbors查询的近邻数,就是K
(2)algorithm:
{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’。找到近邻的方式,注意不是计算距离 的方式,与机器学习算法没有什么关系,开发中请使用默认值'auto'
方法:
(1) fit(x, y)
使用X作为训练数据和y作为目标数据
(2) predict(X) 预测提供的数据,得到预测数据
5 sklearn 实现KNN示例
用KNN算法对鸢尾花进行分类
# 用KNN算法对鸢尾花进行分类
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
# 1)获取数据
iris = load_iris()# 只有4个特征, 150个样本
print(iris.data.shape) #(150,4)
# 4个特征的描述 ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
print(iris.feature_names)# 150个目标,对应150个样本的类别
print(iris.target.shape) #(150,)
# 目标值只有0 1 2这三种值,说明150个样本属于三类中的其中一种
print(iris.target) #[0 0 0...1 1 1 ...2 2 2]
# 目标值三种值代表的三种类型的描述。
print(iris.target_names) #['setosa' 'versicolor' 'virginica']# 2)划分数据集
# x_train训练特征,y_train训练目标, x_test测试特征,y_test测试目标
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
# print(x_train.shape, x_test.shape, y_train.shape, y_test.shape) #(112, 4) (38, 4) (112,) (38,)# 3)特征工程:标准化, 只有4个特征
transfer = StandardScaler()
# 对训练特征做标准化, 对测试特征做相同的标准化,因为fit_transform中已经有fit进行计算了,所以对x_test只需要做transform了
# 训练用的什么数据,模式就只能识别什么样的数据。
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4)KNN算法预估器, k=7表示找7个邻近来判断自身类型.
estimator = KNeighborsClassifier(n_neighbors=7)
estimator.fit(x_train, y_train)#该步骤就是estimator根据训练特征和训练目标在自己学习,让它自己变聪敏
# 5)模型评估 测试一下聪敏的estimator能力
# 方法1:直接比对真实值和预测值,
y_predict = estimator.predict(x_test) #y_predict预测的目标结果
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)# 方法2:计算准确率,
score = estimator.score(x_test, y_test)
print("准确率为:\n", score) #0.9473684210526315
(150, 4)
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
(150,)
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 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 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2]
['setosa' 'versicolor' 'virginica']
y_predict:
[0 2 1 2 1 1 1 1 1 0 2 1 2 2 0 2 1 1 1 1 0 2 0 1 2 0 2 2 2 2 0 0 1 1 1 0 0
0]
直接比对真实值和预测值:
[ True True True True True True True False True True True True
True True True True True True False True True True True True
True True True True True True True True True True True True
True True]
准确率为:
0.9473684210526315
6 模型保存与加载
import joblib
# 保存模型
joblib.dump(estimator, "my_ridge.pkl")
# 加载模型
estimator = joblib.load("my_ridge.pkl")
#使用模型预测
y_test=estimator.predict([[0.4,0.2,0.4,0.7]])
print(y_test)
七 模型选择与调优
1 交叉验证
(1) 保留交叉验证HoldOut
HoldOut Cross-validation(Train-Test Split)
在这种交叉验证技术中,整个数据集被随机地划分为训练集和验证集。根据经验法则,整个数据集的近70%被用作训练集,其余30%被用作验证集。也就是我们最常使用的,直接划分数据集的方法。
优点:很简单很容易执行。
缺点1:不适用于不平衡的数据集。假设我们有一个不平衡的数据集,有0类和1类。假设80%的数据属于 “0 “类,其余20%的数据属于 “1 “类。这种情况下,训练集的大小为80%,测试数据的大小为数据集的20%。可能发生的情况是,所有80%的 “0 “类数据都在训练集中,而所有 “1 “类数据都在测试集中。因此,我们的模型将不能很好地概括我们的测试数据,因为它之前没有见过 “1 “类的数据。
缺点2:一大块数据被剥夺了训练模型的机会。
在小数据集的情况下,有一部分数据将被保留下来用于测试模型,这些数据可能具有重要的特征,而我们的模型可能会因为没有在这些数据上进行训练而错过。
(2) K-折交叉验证(K-fold)
(K-fold Cross Validation,记为K-CV或K-fold)
K-Fold交叉验证技术中,整个数据集被划分为K个大小相同的部分。每个分区被称为 一个”Fold”。所以我们有K个部分,我们称之为K-Fold。一个Fold被用作验证集,其余的K-1个Fold被用作训练集。
该技术重复K次,直到每个Fold都被用作验证集,其余的作为训练集。
模型的最终准确度是通过取k个模型验证数据的平均准确度来计算的。
(3) 分层k-折交叉验证Stratified k-fold
Stratified k-fold cross validation,
K-折交叉验证的变种, 分层的意思是说在每一折中都保持着原始数据中各个类别的比例关系,比如说:原始数据有3类,比例为1:2:1,采用3折分层交叉验证,那么划分的3折中,每一折中的数据类别保持着1:2:1的比例,这样的验证结果更加可信。
(4) 其它验证
去除p交叉验证)
留一交叉验证)
蒙特卡罗交叉验证
时间序列交叉验证
(5)API
from sklearn.model_selection import StratifiedKFold
说明:普通K折交叉验证和分层K折交叉验证的使用是一样的 只是引入的类不同
from sklearn.model_selection import KFold
使用时只是KFold这个类名不一样其他代码完全一样
strat_k_fold=sklearn.model_selection.StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
n_splits划分为几个折叠 shuffle是否在拆分之前被打乱(随机化),False则按照顺序拆分 random_state随机因子
indexs=strat_k_fold.split(X,y)
返回一个可迭代对象,一共有5个折叠,每个折叠对应的是训练集和测试集的下标
然后可以用for循环取出每一个折叠对应的X和y下标来访问到对应的测试数据集和训练数据集 以及测试目标集和训练目标集
for train_index, test_index in indexs:
X[train_index] y[train_index] X[test_index ] y[test_index ]
(6)示例
from sklearn.datasets import load_iris
from sklearn.model_selection import StratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler# 加载数据
iris = load_iris()
X = iris.data
y = iris.target# 初始化分层k-折交叉验证器
#n_splits划分为几个折叠
#shuffle是否在拆分之前被打乱(随机化),False则按照顺序拆分
#random_state随机因子
strat_k_fold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)# 创建一个K近邻分类器实例
knn = KNeighborsClassifier(n_neighbors=7)# 进行交叉验证
accuracies = []
for train_index, test_index in strat_k_fold.split(X, y):
print(train_index, test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]# 数据预处理(标准化)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)# 使用K近邻分类器进行训练
knn.fit(X_train_scaled, y_train)
# 输出每次折叠的准确性得分
score = knn.score(X_test,y_test)
print(score)
accuracies.append(score)#把分数添加到外面列表中
print(sum(accuracies)/len(accuracies))#平均得分#使用StratifiedKFold来创建5个折叠,每个折叠中鸢尾花数据集的类别分布与整体数据集的分布一致。然后我们对每个折叠进行了训练和测试,计算了分类器的准确性。
2 超参数搜索
超参数搜索也叫网格搜索(Grid Search)
比如在KNN算法中,k是一个可以人为设置的参数,所以就是一个超参数。网格搜索能自动的帮助我们找到最好的超参数值。
3 sklearn API
class sklearn.model_selection.GridSearchCV(estimator, param_grid)
说明:
同时进行交叉验证(CV)、和网格搜索(GridSearch),GridSearchCV实际上也是一个估计器(estimator),同时它有几个重要属性:
best_params_ 最佳参数
best_score_ 在训练集中的准确率
best_estimator_ 最佳估计器
cv_results_ 交叉验证过程描述
best_index_最佳k在列表中的下标
参数:
estimator: scikit-learn估计器实例
param_grid:以参数名称(str)作为键,将参数设置列表尝试作为值的字典
示例: {"n_neighbors": [1, 3, 5, 7, 9, 11]}
cv: 确定交叉验证切分策略,值为:
(1)None 默认5折
(2)integer 设置多少折
如果估计器是分类器,使用"分层k-折交叉验证(StratifiedKFold)"。在所有其他情况下,使用KFold。
4 示例-鸢尾花分类
用KNN算法对鸢尾花进行分类,添加网格搜索和交叉验证
# 用KNN算法对鸢尾花进行分类,添加网格搜索和交叉验证
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCVdef knn_iris_gscv():
# 1)获取数据
iris = load_iris()
# 2)划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)
# 3)特征工程:标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4)KNN算法预估器, 这里就不传参数n_neighbors了,交给GridSearchCV来传递
estimator = KNeighborsClassifier()
# 加入网格搜索与交叉验证, GridSearchCV会让k分别等于1,2,5,7,9,11进行网格搜索偿试。cv=10表示进行10次交叉验证
estimator = GridSearchCV(estimator, param_grid={"n_neighbors": [1, 3, 5, 7, 9, 11]}, cv=10)
estimator.fit(x_train, y_train)# 5)模型评估
# 方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)# 方法2:计算准确率
score = estimator.score(x_test, y_test)
print("在测试集中的准确率为:\n", score) #0.9736842105263158# 最佳参数:best_params_
print("最佳参数:\n", estimator.best_params_) #{'n_neighbors': 3}, 说明k=3时最好
# 最佳结果:best_score_
print("在训练集中的准确率:\n", estimator.best_score_) #0.9553030303030303
# 最佳估计器:best_estimator_
print("最佳估计器:\n", estimator.best_estimator_) # KNeighborsClassifier(n_neighbors=3)
# 交叉验证结果:cv_results_
print("交叉验证过程描述:\n", estimator.cv_results_)
#最佳参数组合的索引:最佳k在列表中的下标
print("最佳参数组合的索引:\n",estimator.best_index_)
#通常情况下,直接使用best_params_更为方便
return Noneknn_iris_gscv()
八 朴素贝叶斯分类
1 贝叶斯分类理论
假设现在我们有一个数据集,它由两类数据组成,数据分布如下图所示:
我们现在用p1(x,y)表示数据点(x,y)属于类别1(图中红色圆点表示的类别)的概率,用p2(x,y)表示数据点(x,y)属于类别2(图中蓝色三角形表示的类别)的概率,那么对于一个新数据点(x,y),可以用下面的规则来判断它的类别:
-
如果p1(x,y)>p2(x,y),那么类别为1
-
如果p1(x,y)<p2(x,y),那么类别为2
也就是说,我们会选择高概率对应的类别。这就是贝叶斯决策理论的核心思想,即选择具有最高概率的决策。已经了解了贝叶斯决策理论的核心思想,那么接下来,就是学习如何计算p1和p2概率。
2 条件概率
在学习计算p1 和p2概率之前,我们需要了解什么是条件概率(Conditional probability),就是指在事件B发生的情况下,事件A发生的概率,用P(A|B)来表示。
根据文氏图,可以很清楚地看到在事件B发生的情况下,事件A发生的概率就是P(A∩B)除以P(B)。
𝑃(𝐴|𝐵)=𝑃(𝐴∩𝐵)/𝑃(𝐵)
因此,
𝑃(𝐴∩𝐵)=𝑃(𝐴|𝐵)𝑃(𝐵)
同理可得,
𝑃(𝐴∩𝐵)=𝑃(𝐵|𝐴)𝑃(𝐴)
即
𝑃(𝐴|𝐵)=𝑃(B|A)𝑃(𝐴)/𝑃(𝐵)
这就是条件概率的计算公式。
3 全概率公式
除了条件概率以外,在计算p1和p2的时候,还要用到全概率公式,因此,这里继续推导全概率公式。
假定样本空间S,是两个事件A与A'的和。
上图中,红色部分是事件A,绿色部分是事件A',它们共同构成了样本空间S。
在这种情况下,事件B可以划分成两个部分。
即:
𝑃(𝐵)=𝑃(𝐵∩𝐴)+𝑃(𝐵∩𝐴′)
在上面的推导当中,我们已知
𝑃(𝐵∩𝐴)=𝑃(𝐵|𝐴)𝑃(𝐴)
所以:
𝑃(𝐵)=𝑃(𝐵|𝐴)𝑃(𝐴)+𝑃(𝐵|𝐴′)𝑃(𝐴′)
这就是全概率公式。它的含义是,如果A和A'构成样本空间的一个划分,那么事件B的概率,就等于A和A'的概率分别乘以B对这两个事件的条件概率之和。
将这个公式代入上一节的条件概率公式,就得到了条件概率的另一种写法:
$P(A|B)=\frac{P(B|A)P(A)}{P(B|A)P(A)+P(B|A^,)P(A^,)}$
4 贝叶斯推断
对条件概率公式进行变形,可以得到如下形式:
我们把P(A)称为"先验概率"(Prior probability),即在B事件发生之前,我们对A事件概率的一个判断。
P(A|B)称为"后验概率"(Posterior probability),即在B事件发生之后,我们对A事件概率的重新评估。
P(B|A)/P(B)称为"可能性函数"(Likelyhood),这是一个调整因子,使得预估概率更接近真实概率。
所以,条件概率可以理解成下面的式子:
后验概率 = 先验概率x调整因子
这就是贝叶斯推断的含义。我们先预估一个"先验概率",然后加入实验结果,看这个实验到底是增强还是削弱了"先验概率",由此得到更接近事实的"后验概率"。
5 朴素贝叶斯推断
理解了贝叶斯推断,那么让我们继续看看朴素贝叶斯。贝叶斯和朴素贝叶斯的概念是不同的,区别就在于“朴素”二字,朴素贝叶斯对条件概率分布做了条件独立性的假设。 比如下面的公式,假设有n个特征:
根据贝叶斯定理,后验概率 P(a|X) 可以表示为:
$P(a|X) = \frac{P(X|a)P(a)}{P(X)}$
其中:
-
P(X|a) 是给定类别 ( a ) 下观测到特征向量 $X=(x_1, x_2, ..., x_n) $的概率;
-
P(a) 是类别 a 的先验概率;
-
P(X) 是观测到特征向量 X 的边缘概率,通常作为归一化常数处理。
朴素贝叶斯分类器的关键假设是特征之间的条件独立性,即给定类别 a ,特征 $x_i$ 和 $x_j$ (其中 $i \neq j$ 相互独立。)
因此,我们可以将联合概率 P(X|a) 分解为各个特征的概率乘积:
$P(X|a) = P(x_1, x_2, ..., x_n|a) = P(x_1|a)P(x_2|a)...P(x_n|a)$
将这个条件独立性假设应用于贝叶斯公式,我们得到:
$P(a|X) = \frac{P(x_1|a)P(x_2|a)...P(x_n|a)P(a)}{P(X)}$
这样,朴素贝叶斯分类器就可以通过计算每种可能类别的条件概率和先验概率,然后选择具有最高概率的类别作为预测结果。
这样我们就可以进行计算了。如果有些迷糊,让我们从一个例子开始讲起,你会看到贝叶斯分类器很好懂,一点都不难。
示例:
p(a|X) = p(X|a)* p(a)/p(X) #贝叶斯公式
p(X|a) = p(x1,x2,x3...xn|a) = p(x1|a)*p(x2|a)*p(x3|a)...p(xn|a)
p(X) = p(x1,x2,x3...xn) = p(x1)*p(x2)*p(x3)...p(xn)
p(a|X) = p(x1|a)*p(x2|a)*p(x3|a)...p(xn|a) * p(a) / p(x1)*p(x2)*p(x3)...p(xn) #朴素贝叶斯公式P(好瓜)=(好瓜数量)/所有瓜
P(坏瓜)=(坏瓜数量)/所有瓜
p(纹理清晰)=(纹理清晰数量)/所有瓜
p(纹理清晰|好瓜)= 好瓜中纹理清晰数量/好瓜数量
p(纹理清晰|坏瓜)= 坏瓜中纹理清晰数量/坏瓜数量p(好瓜|纹理清晰,色泽清绿,鼓声沉闷)
=【p(好瓜)】*【p(纹理清晰,色泽清绿,鼓声沉闷|好瓜)】/【p(纹理清晰,色泽清绿,鼓声沉闷)】
=【p(好瓜)】*【p(纹理清晰|好瓜)*p(色泽清绿|好瓜)*p(鼓声沉闷|好瓜)】/【p(纹理清晰)*p(色泽清绿)*p(鼓声沉闷)】p(坏瓜|纹理清晰,色泽清绿,鼓声沉闷)
=【p(坏瓜)*p(纹理清晰|坏瓜)*p(色泽清绿|坏瓜)*p(鼓声沉闷|坏瓜)】/【p(纹理清晰)*p(色泽清绿)*p(鼓声沉闷)】从公式中判断"p(好瓜|纹理清晰,色泽清绿,鼓声沉闷)"和"p(坏瓜|纹理清晰,色泽清绿,鼓声沉闷)"时,因为它们的分母
值是相同的,[值都是p(纹理清晰)*p(色泽清绿)*p(鼓声沉闷)],所以只要计算它们的分子就可以判断是"好瓜"还是"坏瓜"之间谁大谁小了,所以没有必要计算分母
p(好瓜) = 6/10
p(坏瓜)=4/10
p(纹理清晰|好瓜) = 4/6
p(色泽清绿|好瓜) = 4/6
p(鼓声沉闷|好瓜) = 2/6
p(纹理清晰|坏瓜) = 1/4
p(色泽清绿|坏瓜) = 1/4
p(鼓声沉闷|坏瓜) = 1/4
把以上计算代入公式的分子
p(好瓜)*p(纹理清晰|好瓜)*p(色泽清绿|好瓜)*p(鼓声沉闷|好瓜) = 4/45
p(坏瓜)*p(纹理清晰|坏瓜)*p(色泽清绿|坏瓜)*p(鼓声沉闷|坏瓜) = 1/160
所以
p(好瓜|纹理清晰,色泽清绿,鼓声沉闷) > p(坏瓜|纹理清晰,色泽清绿,鼓声沉闷),
所以把(纹理清晰,色泽清绿,鼓声沉闷)的样本归类为好瓜作业?
当样本为(纹理模糊、色泽乌黑、鼓声浊响)时归类为好瓜还是坏瓜
6 拉普拉斯平滑系数
某些事件或特征可能从未出现过,这会导致它们的概率被估计为零。然而,在实际应用中,即使某个事件或特征没有出现在训练集中,也不能完全排除它在未来样本中出现的可能性。拉普拉斯平滑技术可以避免这种“零概率陷阱”
公式为:
一般α取值1,m的值为总特征数量
通过这种方法,即使某个特征在训练集中从未出现过,它的概率也不会被估计为零,而是会被赋予一个很小但非零的值,从而避免了模型在面对新数据时可能出现的过拟合或预测错误
比如计算判断新瓜(纹理清晰,色泽淡白,鼓声沉闷)是好和坏时,因为在样本中色泽淡白没有出现,导致出现0值,会影响计算结果,要采用拉普拉斯平滑系数
p(好瓜|纹理清晰,色泽淡白,鼓声沉闷)
=【p(好瓜)】*【p(纹理清晰|好瓜)*p(色泽淡白|好瓜)*p(鼓声沉闷|好瓜)】/【p(纹理清晰)*p(色泽淡白)*p(鼓声沉闷)】
p(坏瓜|纹理清晰,色泽淡白,鼓声沉闷)
=【p(坏瓜)】*【p(纹理清晰|坏瓜)*p(色泽淡白|坏瓜)*p(鼓声沉闷|坏瓜)】/【p(纹理清晰)*p(色泽淡白)*p(鼓声沉闷)】
p(纹理清晰|好瓜)= (4+1)/(6+3) # +1是因为防止零概率 +3是因为有3个特征(纹理,色泽,鼓声)
p(色泽淡白|好瓜)= (0+1)/(6+3)
p(鼓声沉闷|好瓜) = (2+1)/(6+3)
p(纹理清晰|坏瓜)= (1+1)/(4+3)
p(色泽淡白|坏瓜)= (0+1)/(4+3)
p(鼓声沉闷|坏瓜) = (1+1)/(4+3)
7 sklearn API
sklearn.naive_bayes.MultinomialNB()
estimator.fit(x_train, y_train)
y_predict = estimator.predict(x_test)
8 sklearn 示例
示例:用朴素贝叶斯算法对鸢尾花的分类
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
# 1)获取数据
news =load_iris()
# 2)划分数据集
x_train, x_test, y_train, y_test = train_test_split(news.data, news.target)
# 3)特征工程:不用做标准化
# 4)朴素贝叶斯算法预估器流程
estimator = MultinomialNB()
estimator.fit(x_train, y_train)
# 5)模型评估
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)
# 6)预测
index=estimator.predict([[2,2,3,1]])
print("预测:\n",index,news.target_names,news.target_names[index])
九 决策树-分类
1 概念
1、决策节点 通过条件判断而进行分支选择的节点。如:将某个样本中的属性值(特征值)与决策节点上的值进行比较,从而判断它的流向。
2、叶子节点 没有子节点的节点,表示最终的决策结果。
3、决策树的深度 所有节点的最大层次数。
决策树具有一定的层次结构,根节点的层次数定为0,从下面开始每一层子节点层次数增加
4、决策树优点:
可视化 - 可解释能力-对算力要求低
5、 决策树缺点:
容易产生过拟合,所以不要把深度调整太大了。深度过大时,树会学习到训练数据中的噪声和异常值
是动物 | 会飞 | 有羽毛 | |
---|---|---|---|
1麻雀 | 1 | 1 | 1 |
2蝙蝠 | 1 | 1 | 0 |
3飞机 | 0 | 1 | 0 |
4熊猫 | 1 | 0 | 0 |
是否为动物
是动物 | 会飞 | 有羽毛 | |
---|---|---|---|
1麻雀 | 1 | 1 | 1 |
2蝙蝠 | 1 | 1 | 0 |
4熊猫 | 1 | 0 | 0 |
是否会飞
是动物 | 会飞 | 有羽毛 | |
---|---|---|---|
1麻雀 | 1 | 1 | 1 |
2蝙蝠 | 1 | 1 | 0 |
是否有羽毛
是动物 | 会飞 | 有羽毛 | |
---|---|---|---|
1麻雀 | 1 | 1 | 1 |
2 基于信息增益决策树的建立
信息增益决策树倾向于选择取值较多的属性,在有些情况下这类属性可能不会提供太多有价值的信息,算法只能对描述属性为离散型属性的数据集构造决策树。
根据以下信息构建一棵预测是否贷款的决策树。我们可以看到有4个影响因素:职业,年龄,收入和学历。
职业 | 年龄 | 收入 | 学历 | 是否贷款 | |
---|---|---|---|---|---|
1 | 工人 | 36 | 5500 | 高中 | 否 |
2 | 工人 | 42 | 2800 | 初中 | 是 |
3 | 白领 | 45 | 3300 | 小学 | 是 |
4 | 白领 | 25 | 10000 | 本科 | 是 |
5 | 白领 | 32 | 8000 | 硕士 | 否 |
6 | 白领 | 28 | 13000 | 博士 | 是 |
(1) 信息熵
信息熵描述的是不确定性。信息熵越大,不确定性越大。信息熵的值越小,则D的纯度越高。
假设样本集合D共有N类,第k类样本所占比例为 Pk,则D的信息熵为
(2) 信息增益
信息增益是一个统计量,用来描述一个属性区分数据样本的能力。信息增益越大,那么决策树就会越简洁。这里信息增益的程度用信息熵的变化程度来衡量, 信息增益公式:
(3) 信息增益决策树建立步骤
第一步,计算根节点的信息熵
上表根据是否贷款把样本分成2类样本,"是"占4/6=2/3, "否"占2/6=1/3,
所以
第二步,计算属性的信息增益
<1> "职业"属性的信息增益
在职业中,工人占1/3, 工人中,是否代款各占1/2, 所以有
在职业中,白领占2/3, 白领中,是贷款占3/4, 不贷款占1/4, 所以有
所以有
最后得到职业属性的信息增益为:
<2>" 年龄"属性的信息增益(以35岁为界)
<3> "收入"属性的信息增益(以10000为界,大于等于10000为一类)
<4> "学历"属性的信息增益(以高中为界, 大于等于高中的为一类)
注意: 以上年龄使用35为界,收入使用10000为界,学历使用高中为界,实计API使用中,会有一个参数"深度", 属性中具体以多少为界会被根据深度调整。
第三步, 划分属性
对比属性信息增益发现,"收入"和"学历"相等,并且是最高的,所以我们就可以选择"学历"或"收入"作为第一个
决策树的节点, 接下来我们继续重复1,2的做法继续寻找合适的属性节点(注意:每一次计算出一个节点后都要重新计算该节点的信息熵和后续属性的信息增益)
3 基于基尼指数决策树的建立(了解)
基尼指数(Gini Index)是决策树算法中用于评估数据集纯度的一种度量,基尼指数衡量的是数据集的不纯度,或者说分类的不确定性。在构建决策树时,基尼指数被用来决定如何对数据集进行最优划分,以减少不纯度。
基尼指数的计算
对于一个二分类问题,如果一个节点包含的样本属于正类的概率是 (p),则属于负类的概率是 (1-p)。那么,这个节点的基尼指数 (Gini(p)) 定义为:
$Gini(p) = 1 - p^2 - (1-p)^2 = 2p(1-p) $
对于多分类问题,如果一个节点包含的样本属于第 k 类的概率是 $p_k$,则节点的基尼指数定义为:
$ Gini(p) = 1 - \sum_{k=1}^{K} p_k^2 $
基尼指数的意义
-
当一个节点的所有样本都属于同一类别时,基尼指数为 0,表示纯度最高。
-
当一个节点的样本均匀分布在所有类别时,基尼指数最大,表示纯度最低。
决策树中的应用
在构建决策树时,我们希望每个内部节点的子节点能更纯,即基尼指数更小。因此,选择分割特征和分割点的目标是使子节点的平均基尼指数最小化。具体来说,对于一个特征,我们计算其所有可能的分割点对应的子节点的加权平均基尼指数,然后选择最小化这个值的分割点。这个过程会在所有特征中重复,直到找到最佳的分割特征和分割点。
例如,考虑一个数据集 (D),其中包含 (N) 个样本,特征 (A) 将数据集分割为 $|D_1|$和 $|D_2|$ ,则特征 (A) 的基尼指数为:
$ Gini_A = \frac{|D_1|}{|D|} Gini(D_1) + \frac{|D_2|}{|D|} Gini(D_2) $
其中 $|D_1|$和 $|D_2|$ 分别是子集 $D_1$ 和 $D_2$ 中的样本数量。
通过这样的方式,决策树算法逐步构建一棵树,每一层的节点都尽可能地减少基尼指数,最终达到对数据集的有效分类。
案例:
首先工资有两个取值,分别是0和1。当工资=1时,有3个样本。
所以:
同时,在这三个样本中,工作都是好。
所以:
就有了加号左边的式子:
同理,当工资=0时,有5个样本,在这五个样本中,工作有3个是不好,2个是好。
就有了加号右边的式子:
同理,可得压力的基尼指数如下:
平台的基尼指数如下:
在计算时,工资和平台的计算方式有明显的不同。因为工资只有两个取值0和1,而平台有三个取值0,1,2。所以在计算时,需要将平台的每一个取值都单独进行计算。比如:当平台=0时,将数据集分为两部分,第一部分是平台=0,第二部分是平台!=0(分母是5的原因)。
根据基尼指数最小准则, 我们优先选择工资或者平台=0作为D的第一特征。
我们选择工资作为第一特征,那么当工资=1时,工作=好,无需继续划分。当工资=0时,需要继续划分。
当工资=0时,继续计算基尼指数:
当平台=0时,基尼指数=0,可以优先选择。
同时,当平台=0时,工作都是好,无需继续划分,当平台=1,2时,工作都是不好,也无需继续划分。直接把1,2放到树的一个结点就可以。
4 sklearn API
class sklearn.tree.DecisionTreeClassifier(....)
参数:
criterion "gini" "entropy” 默认为="gini"
当criterion取值为"gini"时采用 基尼不纯度(Gini impurity)算法构造决策树,
当criterion取值为"entropy”时采用信息增益( information gain)算法构造决策树.
max_depth int, 默认为=None 树的最大深度# 可视化决策树
function sklearn.tree.export_graphviz(estimator, out_file="iris_tree.dot", feature_names=iris.feature_names)
参数:
estimator决策树预估器
out_file生成的文档
feature_names节点特征属性名
功能:
把生成的文档打开,复制出内容粘贴到"http://webgraphviz.com/"中,点击"generate Graph"会生成一个树型的决策树图
5 示例
示例1:鸢尾花分类
用决策树对鸢尾花进行分类
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier, export_graphviz# 1)获取数据集
iris = load_iris()# 2)划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)#3)标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)# 4)决策树预估器
estimator = DecisionTreeClassifier(criterion="entropy")estimator.fit(x_train, y_train)
# 5)模型评估,计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)# 6)预测
index=estimator.predict([[2,2,3,1]])
print("预测:\n",index,iris.target_names,iris.target_names[index])# 可视化决策树
export_graphviz(estimator, out_file="iris_tree.dot", feature_names=iris.feature_names)
准确率为:
0.8947368421052632
把文件"iris_tree.dot"内容粘贴到"Webgraphviz"点击"generate Graph"决策树图
示例2:坦尼克号乘客生存
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import DecisionTreeClassifier, export_graphviz
# 1、获取数据
titanic = pd.read_csv("src/titanic/titanic.csv")
titanic.head()
# 筛选特征值和目标值
x = titanic[["pclass", "age", "sex"]]
y = titanic["survived"]#2、数据处理
# 1)缺失值处理, 因为其中age有缺失值。
x["age"].fillna(x["age"].mean(), inplace=True)# 2) 转换成字典, 因为其中数据必须为数字才能进行决策树,所在先转成字典,后面又字典特征抽取,这样之后的数据就会是数字了, 鸢尾花的数据本来就全部是数字,所以不需要这一步。
"""
x.to_dict(orient="records") 这个方法通常用于 Pandas DataFrame 对象,用来将 DataFrame 转换为一个列表,其中列表的每一个元素是一个字典,对应于 DataFrame 中的一行记录。字典的键是 DataFrame 的列名,值则是该行中对应的列值。
假设你有一个如下所示的 DataFrame x:
A B C
0 1 4 7
1 2 5 8
2 3 6 9
执行 x.to_dict(orient="records"),你会得到这样的输出:
[
{'A': 1, 'B': 4, 'C': 7},
{'A': 2, 'B': 5, 'C': 8},
{'A': 3, 'B': 6, 'C': 9}
]
"""
x = x.to_dict(orient="records")
# 3)、数据集划分
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=22)
# 4)、字典特征抽取
transfer = DictVectorizer()
x_train = transfer.fit_transform(x_train) #稀疏矩阵
x_test = transfer.transform(x_test)# 3)决策树预估器
estimator = DecisionTreeClassifier(criterion="entropy", max_depth=8)
estimator.fit(x_train, y_train)# 4)模型评估
# 方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)# 方法2:计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)
# 6)预测
x_test = transfer.transform([{'pclass': '1rd', 'age': 22.0, 'sex': 'female'}])
index=estimator.predict(x_test)
print("预测1:\n",index)#[1] 头等舱的就可以活下来
x_test = transfer.transform([{'pclass': '3rd', 'age': 22.0, 'sex': 'female'}])
index=estimator.predict(x_test)
print("预测2:\n",index)#[0] 3等舱的活不下来# 可视化决策树
export_graphviz(estimator, out_file="titanic_tree.dot", feature_names=transfer.get_feature_names_out())
十 集成学习方法之随机森林
机器学习中有一种大类叫集成学习(Ensemble Learning),集成学习的基本思想就是将多个分类器组合,从而实现一个预测效果更好的集成分类器。集成算法可以说从一方面验证了中国的一句老话:三个臭皮匠,赛过诸葛亮。集成算法大致可以分为:Bagging,Boosting 和 Stacking 三大类型。
(1)每次有放回地从训练集中取出 n 个训练样本,组成新的训练集;
(2)利用新的训练集,训练得到M个子模型;
(3)对于分类问题,采用投票的方法,得票最多子模型的分类类别为最终的类别;
随机森林就属于集成学习,是通过构建一个包含多个决策树(通常称为基学习器或弱学习器)的森林,每棵树都在不同的数据子集和特征子集上进行训练,最终通过投票或平均预测结果来产生更准确和稳健的预测。这种方法不仅提高了预测精度,也降低了过拟合风险,并且能够处理高维度和大规模数据集
1 算法原理
-
随机: 特征随机,训练集随机
-
样本:对于一个总体训练集T,T中共有N个样本,每次有放回地随机选择n个样本。用这n个样本来训练一个决策树。
-
特征:假设训练集的特征个数为d,每次仅选择k(k<d)个来构建决策树。
-
-
森林: 多个决策树分类器构成的分类器, 因为随机,所以可以生成多个决策树
-
处理具有高维特征的输入样本,而且不需要降维
-
使用平均或者投票来提高预测精度和控制过拟合
2 Sklearn API
class sklearn.ensemble.RandomForestClassifier
参数:
n_estimators int, default=100
森林中树木的数量。(决策树个数)criterion {“gini”, “entropy”}, default=”gini” 决策树属性划分算法选择
当criterion取值为“gini”时采用 基尼不纯度(Gini impurity)算法构造决策树,
当criterion取值为 “entropy” 时采用信息增益( information gain)算法构造决策树.
max_depth int, default=None 树的最大深度。
3 示例
坦尼克号乘客生存
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import export_graphviz
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV# 1、获取数据
titanic = pd.read_csv("src/titanic/titanic.csv")
titanic.head()
# 筛选特征值和目标值
x = titanic[["pclass", "age", "sex"]]
y = titanic["survived"]#2、数据处理
# 1)缺失值处理
x["age"].fillna(x["age"].mean(), inplace=True)
# 2) 转换成字典
x = x.to_dict(orient="records")
# 3)、数据集划分
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=22)
# 4)、字典特征抽取
transfer = DictVectorizer()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)'''
#3 预估: 不加网格搜索与交叉验证的代码
estimator = RandomForestClassifier(n_estimators=120, max_depth=5)
# 训练
estimator.fit(x_train, y_train)
'''#3 预估: 加网格搜索与交叉验证的代码
estimator = RandomForestClassifier()
# 参数准备 n_estimators树的数量, max_depth树的最大深度
param_dict = {"n_estimators": [120,200,300,500,800,1200], "max_depth": [5,8,15,25,30]}
# 加入网格搜索与交叉验证, cv=3表示3次交叉验证
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3)
# 训练
estimator.fit(x_train, y_train)
# 5)模型评估
# 方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)# 方法2:计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)'''
加网格搜索与交叉验证的代码
print("最佳参数:\n", estimator.best_params_)
print("最佳结果:\n", estimator.best_score_)
print("最佳估计器:\n", estimator.best_estimator_)
print("交叉验证结果:\n", estimator.cv_results_)
'''
#估计运行花1min
十一 线性回归(重点)
前面介绍了很多分类算法,分类的目标变量是标称型数据,回归是对连续型的数据做出预测。
标称型数据(Nominal Data)是统计学和数据分析中的一种数据类型,它用于分类或标记不同的类别或组别,数据点之间并没有数值意义上的距离或顺序。例如,颜色(红、蓝、绿)、性别(男、女)或产品类别(A、B、C)。
标称数据的特点:
-
无序性:标称数据的各个类别之间没有固有的顺序关系。例如,“性别”可以分为“男”和“女”,但“男”和“女”之间不存在大小、高低等顺序关系。
-
非数值性:标称数据不能进行数学运算,因为它们没有数值含义。你不能对“颜色”或“品牌”这样的标称数据进行加减乘除。
-
多样性:标称数据可以有很多不同的类别,具体取决于研究的主题或数据收集的目的。
-
比如西瓜的颜色,纹理,敲击声响这些数据就属于标称型数据,适用于西瓜分类
连续型数据(Continuous Data)表示在某个范围内可以取任意数值的测量,这些数据点之间有明确的数值关系和距离。例如,温度、高度、重量等
连续型数据的特点包括:
-
可测量性:连续型数据通常来源于物理测量,如长度、重量、温度、时间等,这些量是可以精确测量的。
-
无限可分性:连续型数据的取值范围理论上是无限可分的,可以无限精确地细分。例如,你可以测量一个物体的长度为2.5米,也可以更精确地测量为2.53米,甚至2.5376米,等等。
-
数值运算:连续型数据可以进行数学运算,如加、减、乘、除以及求平均值、中位数、标准差等统计量。
在数据分析中,连续型数据的处理和分析方式非常丰富,常见的有:
-
描述性统计:计算均值、中位数、众数、标准差、四分位数等,以了解数据的中心趋势和分布情况。
-
概率分布:通过拟合概率分布模型,如正态分布、指数分布、伽玛分布等,来理解数据的随机特性。
-
图形表示:使用直方图、密度图、箱线图、散点图等来可视化数据的分布和潜在的模式。
-
回归分析:建立连续型变量之间的数学关系,预测一个或多个自变量如何影响因变量。
-
比如西瓜的甜度,大小,价格这些数据就属于连续型数据,可以用于做回归
1.什么是回归?
回归的目的是预测数值型的目标值y。最直接的办法是依据输入x写出一个目标值y的计算公式。假如你想预测小姐姐男友汽车的功率,可能会这么计算:
HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio
写成中文就是:
小姐姐男友汽车的功率 = 0.0015 * 小姐姐男友年薪 - 0.99 * 收听公共广播的时间
这就是所谓的回归方程(regression equation),其中的0.0015和-0.99称为回归系数(regression weights),求这些回归系数的过程就是回归。一旦有了这些回归系数,再给定输入,做预测就非常容易了。具体的做法是用回归系数乘以输入值,再将结果全部加在一起,就得到了预测值。
2.线性回归
说到回归,一般都是指线性回归(linear regression)。线性回归意味着可以将输入项分别乘以一些常量,再将结果加起来得到输出。线性回归是机器学习中一种有监督学习的算法,回归问题主要关注的是因变量(需要预测的值)和一个或多个数值型的自变量(预测变量)之间的关系.
需要预测的值:即目标变量,target,y
影响目标变量的因素:$X_1,X_2...X_n$,可以是连续值也可以是离散值
因变量和自变量之间的关系:即模型,model,就是我们要求解的
比如1个包子是2元 3个包子是6元 预测5个包子多少钱
列出方程: $y=wx+b$
带入:
2=w*1+b
6=w*3+b
轻易求得 w=2 b=0
模型(x与y的关系): $y=2*x+0$
预测 x=5 时 target_y=2*5+0=10元
上面的方程式我们人类很多年以前就知道了,但是不叫人工智能算法,因为数学公式是理想状态,是100%对的,而人工智能是一种基于实际数据求解最优最接近实际的方程式,这个方程式带入实际数据计算后的结果是有误差的.
人工智能中的线性回归:数据集中,往往找不到一个完美的方程式来100%满足所有的y目标
我们就需要找出一个最接近真理的方程式
比如:
有这样一种植物,在不同的温度下生长的高度是不同的,对不同温度环境下,几颗植物的环境温度(横坐标),植物生长高度(纵坐标)的关系进行了采集,并且将它们绘制在一个二维坐标中,其分布如下图所示:
坐标分别为[4.2, 3.8],[4.2, 2.7],[2.7, 2.4],[0.8, 1.0],[3.7, 2.8],[1.7, 0.9],[3.2, 2.9]。
我们发现这些点好像分布在一条直线的附近,那么我们能不能找到这样一条直线,去“拟合”这些点,这样的话我们就可以通过获取环境的温度大概判断植物在某个温度下的生长高度了。
于是我们的最终目的就是通过这些散点来拟合一条直线,使该直线能尽可能准确的描述环境温度与植物高度的关系。
3.损失函数
数据: [[4.2, 3.8],[4.2, 2.7],[2.7, 2.4],[0.8, 1.0],[3.7, 2.8],[1.7, 0.9],[3.2, 2.9]]
我们假设 这个最优的方程是:
$y=wx+b$
这样的直线随着w和b的取值不同 可以画出无数条
在这无数条中,哪一条是比较好的呢?
我们有很多方式认为某条直线是最优的,其中一种方式:均方差
就是每个点到线的竖直方向的距离平方 求和 在平均 最小时 这条直接就是最优直线
假设: $y=wx+b$
把$x_1,x_2,x_3...$带入进去 然后得出:
$y_1^,=wx_1+b$
$y_2^,=wx_2+b$
$y_3^,=wx_3+b$
...
然后计算${y_1-y_1^,}$ 表示第一个点的真实值和计算值的差值 ,然后把第二个点,第三个点...最后一个点的差值全部算出来
有的点在上面有点在下面,如果直接相加有负数和正数会抵消,体现不出来总误差,平方后就不会有这个问题了
所以最后:
总误差(也就是传说中的损失):
loss1=${(y_1-y_1^,)^2}+{(y_2-y_2^,)^2}+....{(y_n-y_n^,)^2}$
平均误差(总误差会受到样本点的个数的影响,样本点越多,该值就越大,所以我们可以对其平均化,求得平均值,这样就能解决样本点个数不同带来的影响)
这样就得到了传说中的损失函数:
$\bar e = \frac{1}{n} \textstyle\sum{i=1}^{n}(y{i}-w x_{i} - b)^{2}$
怎么样让这个损失函数的值最小呢?
我们先假设b=0 (等后面多元方程求解这个b就解决了)
然后就简单了 算w在什么情况下损失函数的值最小(初中的抛物线求顶点的横坐标,高中求导数为0时)
求得w=0.795时损失函数取得最小值
那我们最终那个真理函数(最优解)就得到了
$y=0.795x+0$
在这个求解的过程中,我们是假设了b=0的 学了多元方程求解后 这个b也是可以求解出来的,因为一元方程是一种特殊的多元方程
总结:
1.实际数据中 x和y组成的点 不一定是全部落在一条直线上
2.我们假设有这么一条直线 $y=wx+b$ 是最符合描述这些点的
3.最符合的条件就是这个方程带入所有x计算出的所有y与真实的y值做 均方差计算
4.找到均方差最小的那个w
5.这样就求出了最优解的函数(前提条件是假设b=0)
4.多参数回归
上面案例中,实际情况下,影响这种植物高度的不仅仅有温度,还有海拔,湿度,光照等等因素:
实际情况下,往往影响结果y的因素不止1个,这时x就从一个变成了n个,$x_1,x_2,x_3...x_n$ 上面的思路是对的,但是求解的公式就不再适用了
案例: 假设一个人健康程度怎么样,由很多因素组成
被爱 | 学习指数 | 抗压指数 | 运动指数 | 饮食情况 | 金钱 | 心态 | 压力 | 健康程度 |
---|---|---|---|---|---|---|---|---|
0 | 14 | 8 | 0 | 5 | -2 | 9 | -3 | 339 |
-4 | 10 | 6 | 4 | -14 | -2 | -14 | 8 | -114 |
-1 | -6 | 5 | -12 | 3 | -3 | 2 | -2 | 30 |
5 | -2 | 3 | 10 | 5 | 11 | 4 | -8 | 126 |
-15 | -15 | -8 | -15 | 7 | -4 | -12 | 2 | -395 |
11 | -10 | -2 | 4 | 3 | -9 | -6 | 7 | -87 |
-14 | 0 | 4 | -3 | 5 | 10 | 13 | 7 | 422 |
-3 | -7 | -2 | -8 | 0 | -6 | -5 | -9 | -309 |
11 | 14 | 8 | 10 | 5 | 10 | 8 | 1 | ? |
求如果karen的各项指标是:
被爱:11 学习指数:14 抗压指数:8 运动指数:10 饮食水平:5 金钱:10 心态:8 压力:1
那么karen的健康程度是多少?
直接能想到的就是**八元一次方程求解**:
$14w_2+8w_3+5w_5+-2w_6+9w_7+-3w_8=399$
$-4w_1+10w_2+6w_3+4w_4+-14w_5+-2w_6+-14w_7+8w_8=-144$
$-1w_1+-6w_2+5w_3+-12w_4+3w_3+-3w_6+2w_7+-2w_8=30$
$5w_1+-2w_2+3w_3+10w_4+5w_5+11w_6+4w_7+-8w_8=126$
$-15w_1+-15w_2+-8w_3+-15w_4+7w_5+-4w_6+-12w_7+2w_8=126$
$11w_1+-10w_2+-2w_3+4w_4+3w_5+-9w_6+-6w_7+7w_8=-87$
$-14w_1+4w_3+-3w_4+5w_5+10w_6+13w_7+7w_8=422$
$-3w_1+-7w_2+-2w_3+-8w_4+-6w_6+-5w_7+-9w_8=-309$
解出 **权重** $w(w_1,w_2...w_8)$ 然后带入即可求出karen的健康程度
权重即重要程度,某一项的权重越大说明它影响最终健康的程度越大
但是这有一个前提:这个八元一次方程组得有解才行
因此我们还是按照损失最小的思路来求**权重** $w(w_1,w_2...w_8)$
**多元线性回归**:
$y^,=w_1x_1+w_2x_2+....w_nx_n+b$
b是截距,我们也可以使用$w_0$来表示只要是个常量就行
$y^,=w_1x_1+w_2x_2+....w_nx_n+w_0$
$y^,=w_1x_1+w_2x_2+....w_nx_n+w_0*1$
那么损失函数就是
$loss=[(y_1-y_1^,)^2+(y_2-y_2^,)^2+....(y_n-y_n^,)^2]/n$
如何求得对应的$W{(w_1,w_2..w_0)}$ 使得loss最小呢?
数学家高斯给出了答案