一.机器学习算法分类

1.监督学习(预测)

监督学习:特征值+目标值,进行训练,得到预测结果可以和标准的结果进行对比

分类:离散型 。 回归:连续型 。

  • 分类:k近邻,贝叶斯分类,决策树与随机森林,逻辑回归,神经网络
  • 回归:线性回归,岭回归

分类问题是监督学习的核心,监督学习中,当输出变量取有限个离散值时,预测问题也变成了分类问题。

无监督学习

无监督学习:只有特征值

  • 聚类:k-means

二.解决python内存不足报错

pandas用read_csv读取csv文件时,读取整个文件,如果文件太大,电脑内存比较小,会报错如下。

为了能顺利进行我们的学习,可以用下面的代码一行一行地读取,最后合并起来

path = 'XXX'
f = open(path)

data = pd.read_csv(path, sep=',',engine = 'python',iterator=True)
loop = True
chunkSize = 1000
chunks = []
index=0
while loop and index <= 1000:    # 指定前1000行
  try:
    print(index)
    chunk = data.get_chunk(chunkSize)
    chunks.append(chunk)
    index+=1

  except StopIteration:
    loop = False
    print("Iteration is stopped.")
print('开始合并')
data = pd.concat(chunks, ignore_index= True)
print('合并完成')

二.k近邻算法

1.k近邻算法基本介绍

思想:通过你的“邻居”来判断你的分类。

如:已知几个电影的特征值和目标值,求某个未知电影的目标值

利用k近邻公式,求出所有已知电影和该未知电影的距离,距离最近的即分类相同。

k近邻算法公式:

2.预处理

标准化:防止数值大的特征值对结果影响更大

3.代码

API:sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, algorithm='auto')

参数:

  • n_neighbors:要找最近的几个邻居,整数(默认5)
  • algorithm:k近邻算法的实现方式,会影响效率。'auto'将根据传递给fit()的值选择最合适的算法。不用去管,用默认的就可以。
    • 'auto':
    • 'ball_tree':
    • 'kd_tree':
    • 'brute':

4.案例

知道一个人的定位坐标、定位准确性、时间等,预测他要到的位置

分析:

  • 特征值:x和y坐标,定位准确性,时间
  • 目标值:要到的位置的id

处理:

  • 原数据时间戳是一个特征,可以转换成(年,月,日,时分秒)格式,把日、时等单独作为一个新的特征。
    • 注:这种处理方法不一定是对的,一切都要看最终预测结果,然后不断调整。
  • 位置太多了,几万个位置,可以把少于指定人数的位置删除。(比如有的位置几万人只有1个人去,没必要预测这个位置,但它又符合我们预测的位置范围,如果不删,反而预测结果会出错)
  • 标准化
import pandas as pd

from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler

# 读取数据
path = r'D:hykMachineLearningkagglefacebook-v-predicting-check-instrain.csv'
f = open(path)
data = pd.read_csv(path, sep=',', engine='python', iterator=True)
loop = True
chunkSize = 1000
chunks = []
index = 0
while loop and index <= 1000:    # 指定前1000行
    try:
        print(index)
        chunk = data.get_chunk(chunkSize)
        chunks.append(chunk)
        index += 1
    except StopIteration:
        loop = False
        print("Iteration is stopped.")
print('开始合并')
data = pd.concat(chunks, ignore_index=True)
print('合并完成')

print(data.head(10))

# 处理数据

# 1、处理时间戳数据 —— pd.to_datetime
time_value = pd.to_datetime(data['time'], unit='s')

# 将日、时添加成新的特征
time_value = pd.DatetimeIndex(time_value)    # 把日期格式转换成字典格式
data['day'] = time_value.day
data['hour'] = time_value.hour

# 把原来时间戳特征删除
data.drop(['time'], axis=1)     # axis=1表示按列删除,和numpy里不一样

# 把去过的人数少于n个的位置删除
place_count = data.groupby('place_id').count()   # 按place_id分组并统计人数
tf = place_count[place_count.row_id>3].reset_index()  # 次数大于3的保留,重置索引
data = data[data['place_id'].isin(tf.place_id)]

# 取出特征值和目标值
y = data['place_id']                # 取出目标值
x = data.drop('place_id', axis=1)   # 删除目标值和row_id那两列,剩下的都是特征值
x = x.drop('row_id', axis=1)   

# 数据分割成训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)

# 特征工程(标准化)
std = StandardScaler()
x_test = std.fit_transform(x_test)    # 将测试集的特征值进行标准化
x_train = std.fit_transform(x_train)  # 将训练集的特征值进行标准化

# 进行算法流程
knn = KNeighborsClassifier(n_neighbors=2)
knn.fit(x_train, y_train)

# 得出预测结果
y_predict = knn.predict(x_test)

print("预测目标所到位置为:", y_predict)
print("预测准确率为:", knn.score(x_test, y_test))

5.总结

k值取多大?有什么影响?

  • k值取很小:容易受异常点影响
  • k值取很大:容易受样本数量影响

性能问题

计算量大,内存开销大。

优点

易于理解,易于实现,无需估计参数,无需训练。

实际开发中基本不会用knn

三.朴素贝叶斯

1.朴素贝叶斯简介

最常用在文章分类。

使用条件:所有特征之间独立。

朴素贝叶斯分类,是计算出属于每个类别的概率,把概率最大的视为其分类。

贝叶斯公式:

公式分三部分:

  • P(C):每个文档类别的概率(某文档类别数/总文档数量)
  • P(W|C):给定类别下特征(被检测文档中出现的词)的概率
    • 计算方法:P(F1|C) = Ni/N (在训练文档中去计算)
    • Ni为该F1词在C类别所有文档中出现的次数
    • N为所属类别C下的文档所有词出现的次数之和
  • P(F1, F2, ...) :预测文档中每个词的概率

例如:

解决某个类别概率为0:拉普拉斯平滑系数

2.代码

API:sklearn.naive_bayes.MultinomialNB(alpha=1.0)

参数:alpha:拉普拉斯平滑系数,默认为1。这个参数不用调,不会影响结果。

不需要调参。

3.案例—新闻分类

数据集

使用sklearn自带的新闻数据集——fetch_20newsgroups(subset='all')

先看一下数据集结构

朴素贝叶斯流程

  • 加载数据,并分割成训练集和测试集
  • 生成文章特征词——用tf-idf
  • 朴素贝叶斯进行估计
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB

news = fetch_20newsgroups(subset='all')

# 分割成训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.25)

# 生成文章特征词
tf = TfidfVectorizer()
x_train = tf.fit_transform(x_train)   # 用训练集去统计每个词的重要性
x_test = tf.transform(x_test) 

# 朴素贝叶斯算法预测
mlt = MultinomialNB()
mlt.fit(x_train, y_train)
y_predict = mlt.predict(x_test)

# 得出预测结果和准确率
print("预测的文章分类为:", y_predict)
print("准确率为:", mlt.score(x_test, y_test))

4.总结

朴素贝叶斯算法很看重训练集,如果训练集误差大,结果也不好。

朴素贝叶斯算法不需要调参。但也因此要提高准确率十分困难

优点:

  • 有数学理论支撑,分类效率稳定
  • 对缺失参数不敏感
  • 分类准确度高,速度快

缺点:

  • 需要特征之间独立,如果特征之间有关联,效果不好
    • 对于文章分类,即假设了文章当中的词语之间是独立,没有关系的。

朴素贝叶斯最擅长于文本分类,但现在文本分类一般也不用朴素贝叶斯,而是用神经网络。

四.准确率和召回率

1.分类模型的评估

准确率

  • estimator.score()

召回率

即我们想要的类别能被真正检测出来的概率。

比如在预测患者是否得癌症时,我们宁可预测多了,也不能放过每一个癌症患者。100个患者中,有20个患癌症,我们另可预测出30个,包含这全部20个人(召回率100%),也不愿只预测到19个,虽然准确率更高,但召回率低了。

API:sklearn.metrics.classification_report(y_true, y_pred, target_names=None)

  • y_true:真实目标值
  • y_pred:预测目标值
  • target_names:目标类别名称
  • 返回值:每个类别精确率和召回率

五.决策树

1.认识决策树

本质是通过多重判断分类,生成的树。

按什么顺序排序的?比如为什么要把年龄排在第一位?

  • 因为年龄这一特征的信息增益最大。能最大程度减少不确定性,
  • 相当于把年龄排在最前面,第一次就能筛掉更多的人。

2.信息论基础——银行贷款分析

分类依据(按什么分类顺序画出决策图)

较常见的:按信息增益最大原则

计算信息增益:g(D,A) = H(D) - H(D|A);A:特征,D:训练集,H(D):信息熵,H(D|A):条件熵。

比如在该数据集中:

  • 数据集信息熵:H(D(类别)) = -(9/15log(9/15)+6/15log(6/15)) = 0.971
  • H(青年) = -(2/5log(2/5)+3/5log(3/5)) = ......(中年、老年的信息熵也一样,不详细计算了)
  • “年龄”的信息增益:g(D, 年龄) = H(D) - H(D'|年龄) = 0.971-[1-3H(青年)+1/3H(中年)+1/3H(老年)]=......

其他分类原则

注:sklearn默认划分原则是 基尼系数,因为它的划分更加细致。

3.决策树API

API:`sklearn.tree.DecisionTreeClassifier(criterian='gini', max_depth=None, random_state=None)

  • criterion:划分依据,默认是基尼系数,可以选择信息增益'entropy'
  • max_depth:树的深度
  • random_state:随机数种子

方法:

  • decision_path:返回决策树的路径

4.实例:泰塔尼克号生存乘客分类

数据集特征包括:票的类别,存货,乘坐班,年龄,登陆地,年龄......,其中年龄的部分数据丢失。

筛选出特征值和目标值

特征值:假设有影响的是——性别,年龄,船舱,船票价格

目标值:是否存活

import pandas as pd
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import DecisionTreeClassifier, export_graphviz

# 获取数据
titannic = pd.read_csv("http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic.txt")
# print(titannic.info())

# 选取一些特征
x = titannic[["pclass", "age", "sex"]]
y = titannic["survived"]

# 处理缺失值
x["age"].fillna(x["age"].mean(), inplace=True)

# 数据集分隔
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
# 字典特征抽取
dv = DictVectorizer(sparse=False)
# print(x_train.to_dict(orient="record"))
x_train = dv.fit_transform(x_train.to_dict(orient="records"))
# print(dv.get_feature_names())
x_test = dv.transform(x_test.to_dict(orient="records"))

# 决策树进行预测
dec = DecisionTreeClassifier()
dec.fit(x_train, y_train)

print("预测的准确率:", dec.score(x_test, y_test))
# 导出决策树
export_graphviz(dec, out_file="titannic_tree.dot", feature_names=dv.get_feature_names())

5.决策树的优缺点以及改进

优点:

  • 简单的理解和解释,树木可视化。
  • 需要很少的数据准备。其他技术通常需要数据归一化,需要创建虚拟变量,并删除空值。但注意,此模块不支持缺少值。
  • 使用树的成本(即,预测数据)在用于训练树的数据点的数量上是对数的。

缺点:

  • 决策树学习者可以创建不能很好地推广数据的过于复杂的树。这被称为过拟合。修剪(目前不支持)的机制,设置叶节点所需的最小采样数或设置树的最大深度是避免此问题的必要条件。
  • 决策树可能不稳定,因为数据的小变化可能会导致完全不同的树被生成。通过使用合奏中的决策树来减轻这个问题。

改进:

  • 减枝cart算法
  • 随机森林

六.随机森林

1.随机森林介绍

集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成单预测,因此优于任何一个单分类的做出预测。

什么是随机森林?

在机器学习中,随机森林是一个包含多个决策树的分类器,并且其输出的类别是由各树输出的众数而定。

2.算法

具体实现:根据下列算法而建造每棵树:

  • 用N来表示训练用例(样本)的个数,M表示特征数目。
  • 输入特征数目m,用于确定决策树上一个节点的决策结果;其中m应远小于M。
  • 从N个训练用例(样本)中以有放回抽样的方式,取样N次,形成一个训练集(即bootstrap取样),并用未抽到的用例(样本)作预测,评估其误差。
  • 对于每一个节点,随机选择m个特征,决策树上每个节点的决定都是基于这些特征确定的。根据这m个特征,计算其最佳的分裂方式。

3.API

API:class sklearn.ensemble.RandomForestClassifier(n_estimators=10, criterion=’gini’,
max_depth=None, bootstrap=True, random_state=None)

参数:

  • n_estimators:integer,optional(default = 10) 森林里的树木数量
  • criteria:string,可选(default =“gini”)分割特征的测量方法
  • max_depth:integer或None,可选(默认=无)树的最大深度
  • bootstrap:boolean,optional(default = True)是否在构建树时使用放回抽样

4.案例

由之前的泰坦尼克号预测改造

from sklearn.ensemble import RandomForestClassifier
...
# 随机森林进行预测
rf = RandomForestClassifier()

# 网格搜索与交叉认证
param = {"n_estimators": [120, 200, 300, 400, 500, 800, 1200], "max_depth": [3, 5, 15, 25, 30]}
gc = GridSearchCV(rf, param_grid=param, cv=2)
gc.fit(x_train, y_train)

print("准确率为:", gc.score(x_test, y_test))
print("最佳的模型参数:", gc.best_params_)

5.优点

  • 在当前所有算法中,具有极好的准确率
  • 能够有效地运行在大数据集上
  • 能够处理具有高维特征的输入样本,而且不需要降维
  • 能够评估各个特征在分类问题上的重要性
  • 对于缺省值问题也能够获得很好得结果