机器学习概述
机器学习的定义
机器学习是从数据中自动分析获得规律(模型),并利用规律对未知数据进行预测
为什么需要机器学习?
让机器学习程序代替手动步骤,减少企业的成本代替企业的效率,如:
- 解放生产力–智能客服
- 解决专业问题–ET医疗
- 提供社会便利–城市大脑
- 机器学习在各领域带来的价值—医疗、航空、教育、物流、电商
数据集的组成
工具:
- pandas:一个数据读取非常方便以及基本处理数据格式的工具。如缺失值处理、数据转换
- numpy:释放了GIL(全局全局解释器锁,历史遗留问题),真正的多线程
不采用mysql的原因
- 性能瓶颈。读取速度慢
- 格式不符合机器学习要求的数据格式
可用数据集
- Kaggle网址:https://www.kaggle.com/datasets
- UCI数据集网址: http://archive.ics.uci.edu/ml/
- scikit-learn网址:http://scikit-learn.org/stable/datasets/index.html
常用数据集数据的结构组成
- 结构:特征值+目标值
数据的特征工程
特征工程是什么
特征工程是将原始数据转换为更好地代表预测模型的潜在问题的特征的过程,从而提高了对未知数据的模型准确性
特征工程的意义
直接影响预测结果
scikit-learn库介绍
- Python语言的机器学习工具
- Scikit-learn包括许多知名的机器学习算法的实现,
- Scikit-learn文档完善,容易上手,丰富的API,使其在学术界颇受欢迎。
数据的特征抽取使用场景
- 特征抽取针对非连续型数据
- 特征抽取对文本等进行特征值化,特征值化是为了让计算机更好的理解数据
# sklearn特征抽取API:
sklearn.feature_extraction
字典特征数据抽取
对字典数据进行特征值化:
from sklearn.feature_extraction import DictVectorizer
# 实例化
dictVectorizer = DictVectorizer()
# 调用 fit_transform
# 默认返回值:返回sparse矩阵(离散) scipy
data = dictVectorizer.fit_transform(
[{'city': '北京', 'temperature': 100}, {'city': '上海', 'temperature': 60}, {'city': '深圳', 'temperature': 30}])
print(data)
# 特征名称列表
print(dictVectorizer.get_feature_names())
# 返回字典既转换之前数据格式
print(dictVectorizer.inverse_transform(data))
输出:
# 离散解决内存
(0, 1) 1.0
(0, 3) 100.0
(1, 0) 1.0
(1, 3) 60.0
(2, 2) 1.0
(2, 3) 30.0
# DictVectorizer(sparse=False)
# 对应 one-hot 编码
# [[ 0. 1. 0. 100.]
# [ 1. 0. 0. 60.]
# [ 0. 0. 1. 30.]]
['city=上海', 'city=北京', 'city=深圳', 'temperature']
[{'city=北京': 1.0, 'temperature': 100.0}, {'city=上海': 1.0, 'temperature': 60.0}, {'city=深圳': 1.0, 'temperature': 30.0}]
one-hot
one-hot 编码:为每个类别生成一个布尔列,对于每一个样本,每列只有一个可以为该样本取值 1。
https://hackernoon.com/what-is-one-hot-encoding-why-and-when-do-you-have-to-use-it-e3c6186d008f
╔════════════╦═════════════════╦════════╗
║ CompanyName Categoricalvalue ║ Price ║
╠════════════╬═════════════════╣════════║
║ VW ╬ 1 ║ 20000 ║
║ Acura ╬ 2 ║ 10011 ║
║ Honda ╬ 3 ║ 50000 ║
║ Honda ╬ 3 ║ 10000 ║
╚════════════╩═════════════════╩════════╝
to:
╔════╦══════╦══════╦════════╦
║ VW ║ Acura║ Honda║ Price ║
╠════╬══════╬══════╬════════╬
║ 1 ╬ 0 ╬ 0 ║ 20000 ║
║ 0 ╬ 1 ╬ 0 ║ 10011 ║
║ 0 ╬ 0 ╬ 1 ║ 50000 ║
║ 0 ╬ 0 ╬ 1 ║ 10000 ║
╚════╩══════╩══════╩════════╝
文本特征提取
CountVectorizer
每个文档的字/词可以使用其出现次数来进行表示:
- 统计所有文章当中所有的词,重复的只看做一次(去重后词的列表,有序)
- 以词的列表为维度,对文章进行词频统计,矩阵元素 a [ i ] [ j ] a[i][j] a[i][j] 表示 j j j 词(词的列表)在第 i i i 个文本下的词频
- 单个字母不统计-单个英文字母没有分类依据
使用场景:用于文本分类、情感分析等:
from sklearn.feature_extraction.text import CountVectorizer
# 实例化
cv = CountVectorizer()
# 调用fit_transform方法输入数据并转换,返回sparse矩阵
data = cv.fit_transform(["life is short,i like python","life is too long,i dislike python"])
# 调用get_feature_names()方法,返回单词列表
print(cv.get_feature_names())
# 利用toarray()方法将sparse矩阵转换array数组
print(data.toarray())
输出:
# 词的列表
['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too']
# 词频统计
[[0 1 1 1 0 1 1 0]
[1 1 1 0 1 1 0 1]]
https://blog.csdn.net/qq_38890412/article/details/107589938#:~:text=CountVectorizer%E6%98%AF%E9%80%9A%E8%BF%87fit_transform%E5%87%BD%E6%95%B0,%E5%88%B0%E8%AF%8D%E9%A2%91%E7%9F%A9%E9%98%B5%E7%9A%84%E7%BB%93%E6%9E%9C%E3%80%82
https://blog.csdn.net/weixin_38278334/article/details/82320307
中文分词
需要对中文进行分词才能详细的进行特征值化:
from sklearn.feature_extraction.text import CountVectorizer
import jieba
# 转换成列表
content1 = list(jieba.cut("今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。"))
content2 = list(jieba.cut("我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。"))
content3 = list(jieba.cut(
"如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"))
# 把列表转换成字符串,用空格隔开
c1 = ' '.join(content1)
c2 = ' '.join(content2)
c3 = ' '.join(content3)
print(c1, c2, c3)
# 特征抽取
cv = CountVectorizer()
data = cv.fit_transform([c1, c2, c3])
print(cv.get_feature_names())
print(data.toarray())
输出:
今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。 我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。 如果 只用 一种 方式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。
['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '这样']
[[0 0 1 0 0 0 2 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 0]
[0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 3 0 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 1]
[1 1 0 0 4 3 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0]]
TfidfVectorizer
TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
- tf(term frequency): 词的频率出现的次数
- idf(inverse document frequency): 逆文档频率公式 = l o g ( 总文档数量 该词出现的文档数量 ) = log(\frac{总文档数量}{该词出现的文档数量}) =log(该词出现的文档数量总文档数量)
- tf * idf: 重要性程度
参考:朴素贝叶斯
from sklearn.feature_extraction.text import TfidfVectorizer
import jieba
con1 = jieba.cut("今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。")
con2 = jieba.cut("我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。")
con3 = jieba.cut("如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。")
# 转换成列表
content1 = list(con1)
content2 = list(con2)
content3 = list(con3)
# 把列表转换成字符串
c1 = ' '.join(content1)
c2 = ' '.join(content2)
c3 = ' '.join(content3)
print(c1, c2, c3)
tf = TfidfVectorizer()
data = tf.fit_transform([c1, c2, c3])
print(tf.get_feature_names())
print(data.toarray())
输出:
今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。 我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。 如果 只用 一种 方式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。
/Users/eddie/PycharmProjects/pythonProject/venv/lib/python3.9/site-packages/sklearn/utils/deprecation.py:87: FutureWarning: Function get_feature_names is deprecated; get_feature_names is deprecated in 1.0 and will be removed in 1.2. Please use get_feature_names_out instead.
warnings.warn(msg, category=FutureWarning)
['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '这样']
# a[i][j] 表示 第 j 个词在第 i 个句子(样本)中重要程度
[[0. 0. 0.21821789 0. 0. 0.
0.43643578 0. 0. 0. 0. 0.
0.21821789 0. 0.21821789 0. 0. 0.
0. 0.21821789 0.21821789 0. 0.43643578 0.
0.21821789 0. 0.43643578 0.21821789 0. 0.
0. 0.21821789 0.21821789 0. 0. 0. ]
[0. 0. 0. 0.2410822 0. 0.
0. 0.2410822 0.2410822 0.2410822 0. 0.
0. 0. 0. 0. 0. 0.2410822
0.55004769 0. 0. 0. 0. 0.2410822
0. 0. 0. 0. 0.48216441 0.
0. 0. 0. 0. 0.2410822 0.2410822 ]
[0.15698297 0.15698297 0. 0. 0.62793188 0.47094891
0. 0. 0. 0. 0.15698297 0.15698297
0. 0.15698297 0. 0.15698297 0.15698297 0.
0.1193896 0. 0. 0.15698297 0. 0.
0. 0.15698297 0. 0. 0. 0.31396594
0.15698297 0. 0. 0.15698297 0. 0. ]]
特征预处理
通过特定的统计方法(数学方法)将数据转换成算法要求的数据。
一般将样本+特征按照矩阵来表示,列对应特征,行对应样本
归一化
特点:通过对原始数据进行变换把数据映射到(默认为[0,1])之间
使得某一特征对最终结果不会造成更大影响,需要进行归一化
x ′ = x − m i n m a x − m i n x ′ ′ = x ′ ∗ ( m x − m i ) + m i x' = \frac{x - min}{max - min} \\ x'' = x' * (m_x - m_i) + m_i x′=max−minx−minx′′=x′∗(mx−mi)+mi
其中 m a x max max m i n min min 为列最大最小, m x m_x mx m i m_i mi 为指定区间一般取 m x = 1 m_x = 1 mx=1 m i = 0 m_i = 0 mi=0, x x x 是原始数据, x ′ ′ x'' x′′ 是最终结果,
from sklearn.preprocessing import MinMaxScaler
# 修改feature_range参数来控制缩放范围,默认(0,1)
mm = MinMaxScaler(feature_range=(2, 3))
data = mm.fit_transform([{90, 2, 10, 40}, [60, 4, 15, 45], [75, 3, 13, 46]])
print(data)
[[3. 2. 2. 2. ]
[2. 3. 3. 2.83333333]
[2.5 2.5 2.6 3. ]]
归一化总结
如果数据中异常点较多,会有什么影响?
- 注意在特定场景下最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,
- 所以这种方法鲁棒性较差,只适合传统精确小数据场景。
标准化
通过对原始数据进行变换把数据变换到均值为0, 方差为1 范围内
使得某一特征对最终结果不会造成更大影响,需要进行归一化
x ′ = x − m e a n σ x' = \frac{x - mean}{\sigma} x′=σx−mean
其中, σ \sigma σ 是标准差
对比:
- 对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变
- 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改
from sklearn.preprocessing import StandardScaler
# 处理之后每列来说所有数据都聚集在均值0附近方差为1
std = StandardScaler()
data = std.fit_transform([[1., -1., 3.], [2., 4., 2.], [4., 6., -1.]])
print(data)
总结:
标准化在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。
缺失值处理
- 删除-如果每列或者行数据缺失值达到一定的比例,建议放弃整行或者整列
- 插补-可以通过缺失值每行或者每列(一般按特征维度)的平均值、中位数来填充
from sklearn.impute import SimpleImputer
import numpy as np
# NaN, nan
im = SimpleImputer(missing_values=np.nan, strategy='mean')
data = im.fit_transform([[1, 2], [np.nan, 3], [7, 6]])
print(data)
https://scikit-learn.org/stable/modules/impute.html