(原创)一个完整的机器学习项目是怎么建立起来的

在这篇文章中,将介绍机器学习项目的流程

明确问题

首先,我们需要预览这个项目。项目的目的是什么,以房价预测为例,数据为StatLib的加州房产数据,那么目的就是预测街区的房产价格中位数。

划定问题及分析

要知道商业目的是什么,毕竟建立模型不是最终目的。比如说,目的是输出一个价格传给另一套系统来判断是否值得投资以及利润是多少。

要知道现在的解决方案效果怎么样,比如会给出一个现解决方案的误差率是alpha。

现在我们可以进一步研究问题,明确这个问题是监督/非监督,还是强化模型?是分类/回归,还是聚类等其他。要使用批量学习还是线上学习?

分析,我们有房价的值,所以是一个监督问题;我们最终是要预测得到房价中位数,因此是一个回归问题,而且是一个多变量预测回归,因为有很多影响参数;另外,没有连续的数据流入,没有特别需求需要对数据变动作出快速适应。数据量不大可以放到内存中,因此批量学习就可以。【如果数据量很大,你可以要么在多个服务器上对批量学习做拆分(使用 MapReduce 技术,后面会看到),或是使用线上学习】

选择性能指标

在这里我们需要选择一个评价指标,回归问题的典型指标是均方根误差RMSE,它表征的是系统预测误差的标准差。

另外,也可以使用差平方绝对误差。

核实假设

再一次核实之前的分析是否准确,需要联系下游的处理进行检查。

获取数据

创建工作空间

比如python jupyter及相应的库文件(如numpy, pandas, scipy, 及sklearn等)和框架(tf等)

下载数据

一般来说,可以从数据库中下载数据,但是对于数据库一般需要密码及权限。在这里,我们可以直接从网页数据,当然,这是具体问题具体分析的。

查看数据

下载好数据后,我们需要查看一下数据的结果,预览一下。基本用到以下代码

import pandas as pd
data=pd.read_csv(‘路径‘)
data.head()
data.info()#返回特征的数量及类型
data.describe()#返回数量、均值、标准差、最值等信息

另外也可以使用柱状图通过可视化查看数据的分布,代码:

%matplotlib inline   # only in a Jupyter notebook
import matplotlib.pyplot as plt
data.hist(bins=50, figsize=(20,15))
plt.show()#在jupyter中可以不加这条语句

hist()方法依赖于 Matplotlib,后者依赖于用户指定的图形后端以打印到屏幕上。因此在画图之前,你要指定 Matplotlib 要使用的后端。

最简单的方法是使用 Jupyter 的魔术命令%matplotlib inline。它会告诉 Jupyter 设定好 Matplotlib,以使用 Jupyter 自己的后端。绘图就会在 notebook 中渲染了。

创建测试集

在查看数据前,最好先创建一下测试集,以免查看数据后因为思维定势影响测试集的选择。

一种方法是可以随机选择测试集,比如随机选择20%的数据作为测试集,但是这样当数据集更新时,测试集会变化,我们可以使用随机数处理。代码:

from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)

另外,随机取数有可能丢失掉关键特征的分布。比如,有一个特征A对最终标签的贡献很大(两者之间相关性很强),

那么我们也应该在测试集中保证A的分布符合原数据集的分布趋势。这时可以使用分层采样。代码:

data["A_new"] = np.ceil(data["A"] / 1.5)
data["A_new"].where(data["A_new"] < 5, 5.0, inplace=True)#这两条语句是对数据生成一个新的标签,表征A的分层(分布),这要具体问题具体分析
from sklearn.model_selection import StratifiedShuffleSplit

split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)

for train_index, test_index in split.split(data, data["A_new"]):#按照A_new对data进行划分测试集训练集
    strat_train_set = data.loc[train_index]
    strat_test_set = data.loc[test_index]

可通过以下代码检查分层采样的结果:

data["A_new"].value_counts() / len(data)
strat_test_set["A_new"].value_counts() / len(strat_test_set)

注意最后需要将生成的A_new标签删除,用drop命令,代码:

for set in (strat_train_set, strat_test_set):
    set.drop(["A_new"], axis=1, inplace=True)

这样我们就生成了两组训练-测试集,随机的和分层的。

数据可视化及数据探索

数据可视化

经常性的,我们需要首先对数据进行一下观察,可以判断特征与标签的关系以及哪些特征的作用或者影响更大。在这里使用matplotlib库即可,如:

housing.plot(kind="scatter", x="longitude", y="latitude")#散点图看分布

查找关联

可以使用corr()方法计算每对属性间的标准相关系数,如:

corr_m=housing.corr()
print(corr_m[‘median_house_value‘].sort_values(ascending=True))

注意corr()只能表征线性关系,对于非线性关系直接忽视,因此参考性有局限。还有一种检测属性间相关系数的方法时pandas的scatter_matrix函数,如:

from pandas.tools.plotting import scatter_matrix
attributes = ["median_house_value", "median_income", "total_rooms", "housing_median_age"]#只表示这四个的相关性
scatter_matrix(housing[attributes], figsize=(12, 8))

属性组合试验

有时候仅仅使用原有的特征数据的效果并不好,这是可以考虑一下将一些特征组合产生新的特征,比如将人数/家庭,得到每户的人数这样一个特征。如:

housing[‘population_per_household‘]=housing[‘population‘]/housing[‘households‘]

然后可以重新观察相关性。

为机器学习准备数据

不要手工来做,你需要写一些函数,理由如下:

函数可以让你在任何数据集上(比如,你下一次获取的是一个新的数据集)方便地进行重复数据转换。

你能慢慢建立一个转换函数库,可以在未来的项目中复用。

在将数据传给算法之前,你可以在实时系统中使用这些函数。

这可以让你方便地尝试多种数据转换,查看哪些转换方法结合起来效果最好。

有一点需要注意,那就是要时刻记得复制数据,保证后面的数据处理尽量不要影响最初的数据。做好标记。

数据清洗

原数据中会存在缺失值等问题,因此需要对数据进行清洗。这一非常关键的一步。

对于缺失值的处理,有三种方式

1、直接删掉缺失值所在的行;2、如果一个特征的缺失值太多,那么直接删掉该特征;3、对缺失位置进行赋值(用0、中位数或者平均值等)。如:

housing.dropna(housing[‘total_bedrooms‘])
housing.drop(‘total_bedrooms‘,axis=1)
housing[‘total_bedrooms‘].fillna(median)

尽量采用第三种方式,这样可以充分利用原数据。可以使用sklearn的Imputer类来处理缺失值。

from sklearn.preprocessing import Imputer
imputer = Imputer(strategy="median")#创建一个Imputer类
housing_num = housing.drop("ocean_proximity", axis=1)#创建没有文本属性的数据副本
imputer.fit(housing_num)#将类应用于数据,求出median
X = imputer.transform(housing_num)#对数据进行转换,填充缺失值,得到一个numpy数组
housing_tr = pd.DataFrame(X, columns=housing_num.columns)#数组转化为DataFrame格式

处理文本和类别属性

数据中会有一些文本类型,在处理时我们可以使用one-hot对其进行重新编码,这需要两个转换(文本分类到整数分类,再到one-hot向量)

可以用sklearn的LabelBinarizer实现这两个转换

from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer()
housing_cat_1hot = encoder.fit_transform(housing_cat)#得到one-hot向量
print(housing_cat_1hot)

但是,上面的类也应用于标签列的转换,正确的做法时用sklearn即将提供的CategoricalEncoder类,如:

cat_encoder = CategoricalEncoder()
housing_cat_reshaped = housing_cat.values.reshape(-1, 1)
housing_cat_1hot = cat_encoder.fit_transform(housing_cat_reshaped)
print(housing_cat_1hot)

自定义转换器

转换器的作用是将一些数据处理的操作集中在一起执行,比如前面叙述的清洗、属性组合等,另外可以将自制的转换器与sklearn的流水线无缝衔接工作。这一部分的示例代码可以查看自己写的文件(备注:)。这一部分可以将属性组合写在里面。

注意这里可以为属性设置一些超参数,检查这个属性是否地ML的算法有帮助。

特征缩放

这个步骤很重要,针对的是输入数值属性量度的不同问题。比如,年龄属性在20~50,而收入分布在5000~100000,这样的数据应用于算法的性能不会太好。通常情况下不要对目标值进行缩放。

两种方式:

线性函数归一化(min-max-scaling)-减去最小值,再除以最大值与最小值的差值,sklearn的MinMaxScaler

标准化(standardization)-减去平均值,再除以方差,得到的分布具有单位方差。sklearn的StandardScaler

注:所有的数据转换等操作都要分别作用于训练集和测试集,不要向完成的数据集使用。

转换流水线

流水线的作用时创建一种模式,使得数据可以按照一定顺序进行处理和转化。例如下面是一个完整的处理数值和类别属性的流水线:

from sklearn.pipeline import FeatureUnion
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

num_attribs = list(housing_num)
cat_attribs = ["ocean_proximity"]

num_pipeline = Pipeline([
        (‘selector‘, DataFrameSelector(num_attribs)),
        (‘imputer‘, Imputer(strategy="median")),
        (‘attribs_adder‘, CombinedAttributesAdder()),
        (‘std_scaler‘, StandardScaler()),
    ])

cat_pipeline = Pipeline([
        (‘selector‘, DataFrameSelector(cat_attribs)),
        (‘cat_encoder‘, CategoricalEncoder(encoding="onehot-dense")),
    ])

full_pipeline = FeatureUnion(transformer_list=[
        ("num_pipeline", num_pipeline),
        ("cat_pipeline", cat_pipeline),
    ])

使用时调用:

housing_prepared=full_pipeline.fit_transform(housing)#其中housing是分层抽样并drop掉标签值的分好的训练集。

这样调用步骤:num_pipeline->DataFrameSelector->Imputer->CombinedAttributesAdder->StandardScaler->cat_pipeline->DataFrameSelector->CategoricalEncoder,得到处理好的训练集。

其表示分别为:子流水线数据操作-》选择转化器-》缺失值处理-》属性组合-》标准化-》子流水线分类处理-》选择转化器-》分类标记为one-hot向量

对于选择转换器的解释:通过选择对应的属性(数值或分类)、丢弃其它的,来转换数据,并将输出DataFrame转变成一个 NumPy 数组。Scikit-Learn 没有工具来处理 PandasDataFrame,因此我们需要写一个简单的自定义转换器来做这项工作:

#这一部分最好写在前面
from sklearn.base import BaseEstimator, TransformerMixin
class DataFrameSelector(BaseEstimator, TransformerMixin):
    def __init__(self, attribute_names):
        self.attribute_names = attribute_names
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        return X[self.attribute_names].values

至此,我们得到了处理后的训练集(不带标签)housing_prepared,标签集housing_labels,测试集(未经处理,并带标签)。

选择并训练模型

在训练集上训练和评估

到这里我们就可以选择算法模型对数据进行训练学习(其实我们可以发现大多数的工作都集中在数据的预处理上,包括清洗可视化文类属性转化等)。

from sklearn.linear_model import LinearRegression
lin_reg=LinearRegression()
lin_reg.fit(housing_prepared,housing_labels)

评价模型,可以使用均方根误差。

from from sklearn.metrics import mean_squared_error
housing_predictions = lin_reg.predict(housing_prepared)
lin_mse = mean_squared_error(housing_labels, housing_predictions)
lin_rmse = np.sqrt(lin_mse)

当然不仅是线性回归,同样可以使用其他模型,比如决策树模型、随机森林模型,步骤同上。

使用交叉验证做更佳的评价

另外,我们可以使用交叉验证来验证模型,以决策树为例:

from sklearn.model_selection import cross_val_score
scores = cross_val_score(tree_reg, housing_prepared, housing_labels,scoring="neg_mean_squared_error", cv=10)
rmse_scores = np.sqrt(-scores)

以上,随机地将训练集分成十个不同的子集,成为“折”,然后训练评估决策树模型 10 次,每次选一个不用的折来做评估,用其它 9 个来做训练。结果是一个包含 10 个评分的数组。

Scikit-Learn 交叉验证功能期望的是效用函数(越大越好)而不是损失函数(越低越好),因此得分函数实际上与 MSE 相反(即负值),这就是为什么前面的代码在计算平方根之前先计算-scores。

结果查看:

def display_scores(scores):
...     print("Scores:", scores)
...     print("Mean:", scores.mean())
...     print("Standard deviation:", scores.std())
display_scores(tree_rmse_scores)

当然也可以将线性回归和随机森林适用到交叉验证上。另外还可以使用其他算法,比如神经网络、不同核心的支持向量机等。不要将太多时间花在调参上。

到这儿的目标是先列出几个合适的模型列表。

模型微调

网格搜索

使用 Scikit-Learn 的GridSearchCV方法。以针对随机森林为例。

from sklearn.model_selection import GridSearchCV
param_grid = [
    {‘n_estimators‘: [3, 10, 30], ‘max_features‘: [2, 4, 6, 8]},
    {‘bootstrap‘: [False], ‘n_estimators‘: [3, 10], ‘max_features‘: [2, 3, 4]},
  ]
forest_reg = RandomForestRegressor()
grid_search = GridSearchCV(forest_reg, param_grid, cv=5, scoring=‘neg_mean_squared_error‘)
grid_search.fit(housing_prepared, housing_labels)

分析可知,以上训练总共有18 × 5 = 90轮。

参数的最佳组合及最佳估计器:

print(grid_search.best_params_)
print(grid_search.best_estimator_)

随机搜索

当超参数的搜索空间很大时,最好使用RandomizedSearchCV。这个类的使用方法和类GridSearchCV很相似,但它不是尝试所有可能的组合,而是通过选择每个超参数的一个随机值的特定数量的随机组合。

集成方法

另一种微调系统的方法是将表现最好的模型组合起来。

分析最佳模型和它们的误差

通过分析最佳模型,常常可以获得对问题更深的了解。比如,RandomForestRegressor可以指出每个属性对于做出准确预测的相对重要性:

feature_importances = grid_search.best_estimator_.feature_importances_
print(feature_importances)
#将重要性分数与属性名放在一起
extra_attribs = ["rooms_per_hhold", "pop_per_hhold", "bedrooms_per_room"]
cat_one_hot_attribs = list(encoder.classes_)
attributes = num_attribs + extra_attribs + cat_one_hot_attribs
sorted(zip(feature_importances,attributes), reverse=True)#输出重要性和对应的属性名

根据以上重要性分数,我们可以舍弃一些不重要的属性等

用测试集评估系统

终于调试完模型,接下来我们需要用测试集来测试,注意,我们之前分割数据之后,测试集一直没用,这时我们需要先对测试集进行一下处理,比如丢掉标签、流水线处理等。然后再将我们的模型应用上去。

final_model = grid_search.best_estimator_
X_test = strat_test_set.drop("median_house_value", axis=1)
y_test = strat_test_set["median_house_value"].copy()
X_test_prepared = full_pipeline.transform(X_test)
final_predictions = final_model.predict(X_test_prepared)
final_mse = mean_squared_error(y_test, final_predictions)
final_rmse = np.sqrt(final_mse)
print(final_rmse)

到这,我们就基本完成了模型的创建和测试,接下来就需要将结果或者结论展示出来。

启动、监控和维护系统

将以上模型植入公司系统,实现自动化运行。

实践

不要浪费在高级算法上,会使用就可以了。重点在于理解业务和数据,以及数据的处理。

注:此文章参考了GitHub-PeterHo的文章,感谢。

原文地址:https://www.cnblogs.com/rayshaw/p/9037969.html

时间: 2024-10-11 05:50:32

(原创)一个完整的机器学习项目是怎么建立起来的的相关文章

react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)

react全家桶从0到1(最新) 本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redux-saga的核心配置会加以讲解,通过这个项目,可以系统的了解react技术栈的主要知识,避免搭建一次后面就忘记的情况. 从webpack开始 思考一下webpack到底做了什么事情?其实简单来说,就是从入口文件开始,不断寻找依赖,同时为了解析各种不同的文件加载相应的loader,最后生成我们希望的

想要做一个完整的Javaweb项目需要掌握哪些技能

近期,刚刚完整的接触了一个Javaweb的项目,综合自己在做项目的过程,列举了一些所需要用到的技能和知识点,带给还没有真正接触过完整Java Web项目的同学一个比较完整的视角,提供一个所谓的"大局观",也以便于同学们更有针对性地学习. 在前端没有那么火的前几年,或者说在经典的Java Web的开发模式中,我们使用Jsp技术来作为展现层的实现,其实也就是所谓的前端.当然只懂得Jsp是不够的还需要懂html,css,js,ajax等一些前端的基础技术,Jsp技术在其中扮演外层包装的角色.

做一个完整的Hadoop项目

 1. 完整的数据流图 由同ip访问的次数: SQL查询 select ip,count(ip) from tablename Group by ip; 基于Hadoop分析 使用Hadoop分析,需要两轮的Mapreduce处理 Hive不支持对数据的更改和添加 原文地址:https://www.cnblogs.com/zhichun/p/11355777.html

一个完整的mybatis项目,包含增删改查

1.导入jar包,导入相关配置文件,均在自己博客园的文件中 编写mybatis.xml文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "./mybatis-3-config.dtd"> <configuration> &l

一个完整JavaWeb项目历程02 — Hello Servlet

前言 前一篇引入了很多概念性的东西,各种百度谷歌拼起来的一个Hello JavaWeb工程:那又有什么关系呢,只要在学习每天都会接触新概念的东西:尽管做就是了,概念不清楚又有什么关系.目的只有一个:做 一个完整的JavaWeb项目. 一.创建JavaWebServlet项目 请参考前一篇 二.创建一个HelloServlet类 其实包可以不用单独去创建,在创建Servlet的时候,Java package一栏填写包名:com.fwbc.servlet就可以自动创建包. 三.创建一个hello.j

一个完整的项目中,需要的基本gulp

一个完整的项目需要使用gulp的多种功能,包括—— (1)加载各种需要的插件 var concat=require('gulp'); var clean=require(''gulp); 等等.需要的插件放在指定的module文件夹下面,然后再修改文件中修改. (2)启动任务和完成部署任务 我们想要在文件进行操作之前,首先将文件的环境弄好,例如,想把a放在一个目录下,但是这个目录下面有着很多的不需要的文件,所以我们首先需要将这些文件删除—— gulp.task('cleanTask',funct

做一个完整的Java Web项目需要掌握的技能

原文链接:http://blog.csdn.net/JasonLiuLJX/article/details/51494048 最近自己做了几个Java Web项目,有公司的商业项目,也有个人做着玩的小项目,写篇文章记录总结一下收获,列举出在做项目的整个过程中,所需要用到的技能和知识点,带给还没有真正接触过完整Java Web项目的同学一个比较完整的视角,提供一个所谓的"大局观",也以便于同学们更有针对性地学习.当然,这里所用到的例子项目是非常初级,简单的项目,所以大神们就可以不用往下看

做一个完整的Java Web项目需要掌握的技能[转]

转自:http://blog.csdn.net/JasonLiuLJX/article/details/51494048 最近自己做了几个Java Web项目,有公司的商业项目,也有个人做着玩的小项目,写篇文章记录总结一下收获,列举出在做项目的整个过程中,所需要用到的技能和知识点,带给还没有真正接触过完整Java Web项目的同学一个比较完整的视角,提供一个所谓的"大局观",也以便于同学们更有针对性地学习.当然,这里所用到的例子项目是非常初级,简单的项目,所以大神们就可以不用往下看了.

一个完整项目的流程都涉及哪些内容

最近在跟着老师学做一个有关图书馆的项目,目标是做出一个移动端的包含校内图书馆内容的图书馆.上完第一节课,梳理一下有关内容. 第一节课主要介绍了做一个完整的项目的流程都有哪些,涉及哪方面的内容,具体如下: 一.首先需要确定你的目标是什么,即你要做什么.确定你要做的项目是什么,比如我学做的是有关图书馆的项目. 二.项目流程.了解主流IT互联网公司的项目流程及职责,来划分自己需要做内容都有哪些. 三.产品设计.进行需求分析,版本规划,原型设计. (1)需求分析 (2)版本规划 (3)原型设计 这里要推