Kaggle课程 — 机器学习入门 Intro to Machine Learning
本文翻译自kaggle官方网站https://www.kaggle.com/learn/intro-to-machine-learning,仅供参考。
1.决策树
1.1决策树简介
我们将从机器学习模型如何工作以及如何运用的概述开始。你将感到这部分很基础,假如你之前进行过统计建模或机器学习。别担心,很快我们将构建强大的模型。
通过该微课程,你在遇到如下场景时可以构建模型:
你的堂兄投机房地产赚取了数百万美元。由于你对数据科学的兴趣,他愿意成为你的商业合作伙伴。他提供钱,你提供模型来预测不同房屋的价值。
你询问你的堂兄他过去是如何预测房地产价格。他回答说靠直觉。但是,更多的质疑显示,他从过去的房屋中识别出了价格的模式,并且他用这些模式来预测他考虑的新房屋。
机器学习也是同样的方式。我们从决策树模型开始。有许多优秀的模型能够提供更好的预测。但是,决策树易于理解,并且是数据科学中一些优秀模型的基石。
为了简便,我们从可能是最简单的决策树开始。如下图所示:
它把房屋仅分成两类。 对于所关注的任何房屋的预测价格,是同一类房屋的历史平均价格。
我们用数据来决定如何把房屋分成两组,并且把决定预测的价格放在每一组。这一步从数据中捕捉模式的过程叫做拟合fitting
或训练training
模型。用来拟合模型的数据叫做训练数据training data
。
如何拟合模型足够复杂,我们之后讨论。模型拟合之后,你可以在新的数据上运用模型来预测房屋价格。
1.2改进决策树
下面的两个决策树,哪一个更可能是房地产训练数据拟合的结果?
左边的决策树(决策树1)可能更灵敏,因为它捕捉到实际上有更多房间的房屋比有更少房间的房屋卖的价格更高。这个模型最大的缺点就是它没有捕捉到大部分影响房屋的因素,比如卫生间的数量、房屋面积、区位等。
你可以捕捉更多的因素通过使用分支splits
,又叫做更深的树deeper trees
。一个决策树考虑每一个房屋的总面积可能是如下的样子depth 2 tree
:
你通过决策树预测任何房屋的价格,总是通过选择与房屋特征一致的路径。房屋的预测价格位于树的底部。底部的点,我们用来做预测的,又叫做叶片leaf
。
叶片的分叉和值将由数据来决定。因此,是时候检查你将使用的数据了。
2.数据浏览基础
2.1 使用pandas来熟悉你的数据
任何机器学习项目的第一步都是了解你的数据。你将学习使用pandas
库。pandas
是数据科学家首要使用的工具,用来浏览和操纵数据。大多数人将pandas
缩写为pd
,可以用如下命令:
import pandas as pd
pandas
库最重要的部分是DataFrame
。你可以把一个DataFrame
的类型看作是一张表。类似于Excel里面的sheet,或者SQL数据库的table。
pandas
这一类型的数据有强大的方法可以引用。
例如,我们查看澳大利亚墨尔本的房屋价格数据。在实际练习中,你将应用相同的步骤查看爱荷华州的房屋价格数据。
假如墨尔本的数据在如下路径:
../input/melbourne-housing-snapshot/melb_data.csv
我们通过如下命令加载并浏览数据:
# save filepath to variable for easier access
melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv'
#read the data and store data in DataFrame titled melbourne_data
melbourne_data = pd.read_csv(melbourne_file_path)
#print a summary of the data in Melbourne data
melbourne_data.describe()
Rooms Price Distance Postcode Bedroom2 Bathroom Car Landsize BuildingArea YearBuilt Lattitude Longtitude Propertycount
count 13580.000000 1.358000e+04 13580.000000 13580.000000 13580.000000 13580.000000 13518.000000 13580.000000 7130.000000 8205.000000 13580.000000 13580.000000 13580.000000
mean 2.937997 1.075684e+06 10.137776 3105.301915 2.914728 1.534242 1.610075 558.416127 151.967650 1964.684217 -37.809203 144.995216 7454.417378
std 0.955748 6.393107e+05 5.868725 90.676964 0.965921 0.691712 0.962634 3990.669241 541.014538 37.273762 0.079260 0.103916 4378.581772
min 1.000000 8.500000e+04 0.000000 3000.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1196.000000 -38.182550 144.431810 249.000000
25% 2.000000 6.500000e+05 6.100000 3044.000000 2.000000 1.000000 1.000000 177.000000 93.000000 1940.000000 -37.856822 144.929600 4380.000000
50% 3.000000 9.030000e+05 9.200000 3084.000000 3.000000 1.000000 2.000000 440.000000 126.000000 1970.000000 -37.802355 145.000100 6555.000000
75% 3.000000 1.330000e+06 13.000000 3148.000000 3.000000 2.000000 2.000000 651.000000 174.000000 1999.000000 -37.756400 145.058305 10331.000000
max 10.000000 9.000000e+06 48.100000 3977.000000 20.000000 8.000000 10.000000 433014.000000 44515.000000 2018.000000 -37.408530 145.526350 21650.000000
2.2 数据描述
输出结果在原始数据集每一列展示了8个数字。第一个count
,表明有多少行不含缺失值。缺失值由多种原因引起。例如,当统计第1间卧室房屋时候,未收集到第2间卧室房屋数据。我们将来再回到缺失值的话题来。
第二个mean
,也就是平均值。基于此,std
是标准差,用于测量值的分散程度。
为了解释min
,25%
,50%
,75%
,max
。试想一下让每一列从小到大排序。第一个值也就是min
。假如你走到列表中四分之一的位置,你将发现一个数字比25%的值要大,比75%的值要小,这就是25%
,也叫25分位数
。类似的定义50分位数
和75分位数
以及最大值max
。
3.你的第一个机器学习模型
3.1 选择数据建模
你的数据集包含许多变量使你头晕,甚至无法完美地打印出来。你如何削减这个巨大数量的数据使得其更易于理解?
我们用直觉先选择一部分变量开始,接下来的课程将向你展示自动优化变量的统计技巧。
为了选择变量variables
/列名columns
,我们需要查看数据集中所有列名。可以利用DataFrame
中columns
的性质。
import pandas as pd
melbourne_file_path = ''
melbourne_data = pd.read_csv(melbourne_file_path)
melbourne_data.columns
Index(['Suburb', 'Address', 'Rooms', 'Type', 'Price', 'Method', 'SellerG',
'Date', 'Distance', 'Postcode', 'Bedroom2', 'Bathroom', 'Car',
'Landsize', 'BuildingArea', 'YearBuilt', 'CouncilArea', 'Lattitude',
'Longtitude', 'Regionname', 'Propertycount'],
dtype='object')
# The Melbourne data has some missing values (some houses for which some variables weren't recorded.)
# We'll learn to handle missing values in a later tutorial.
# Your Iowa data doesn't have missing values in the columns you use.
# So we will take the simplest option for now, and drop houses from our data.
# Don't worry about this much for now, though the code is:
# dropna drops missing values (think of na as "not available")
melbourne_data = melbourne_data.dropna(axis=0)
有许多方法从你的数据集中选择子集。pandas微课程覆盖了更多这方面的内容,但是,我们目前先关注两种方法:
- 点标记
dot notation
,用来选择“预测目标”prediction target
. - 选择一个列名列表,用来选择“特征”
features
.
3.1.1 选择预测目标
你可以使用点标记提取出一个变量。这单独的一列存储在一个Series
中,宽泛来说与只有一列数据的DataFrame
类似。
我们使用点标记来选择我们想要预测的列,又叫做预测目标。为了简便,预测目标也称为y
。因此,用来保存墨尔本数据中房屋价格的代码如下:
y = melbourne_data.Price
3.1.2 选择特征“Features”
这些输入到模型中的列(稍后用于预测)又叫做“特征”。在我们的模型中,这些列被用来决定房屋价格。有时候,你将使用除目标之外所有的列作为特征。其他时候,你最好使用较少的特征。
到目前,我们将建立一个仅有少数特征的模型。稍后你将看到如何迭代和比较用不同特征建立的模型。
我们选择多种多样的特征通过提供列名列表。列表中的每一项都应该是一个string
。下面是一个例子:
melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'Lattitude', 'Longtitude']
为了简便,把这部分数据叫做X
。
X = melbourne_data[melbourne_features]
让我们快速的回顾一下用来预测房价的数据,使用describe
方法和head
方法,展示前面几行数据。
X.describe()
Rooms Bathroom Landsize Lattitude
count 6196.000000 6196.000000 6196.000000 6196.000000 6196.000000
mean 2.931407 1.576340 471.006940 -37.807904 144.990201
std 0.971079 0.711362 897.449881 0.075850 0.099165
min 1.000000 1.000000 0.000000 -38.164920 144.542370
25% 2.000000 1.000000 152.000000 -37.855438 144.926198
50% 3.000000 1.000000 373.000000 -37.802250 144.995800
75% 4.000000 2.000000 628.000000 -37.758200 145.052700
max 8.000000 8.000000 37000.000000 -37.457090 145.526350
X.head()
Rooms Bathroom Landsize Lattitude Longtitude
1 2 1.0 156.0 -37.8079 144.9934
2 3 2.0 134.0 -37.8093 144.9944
4 4 1.0 120.0 -37.8072 144.9941
6 3 2.0 245.0 -37.8024 144.9993
7 2 1.0 256.0 -37.8060 144.9954
用这些命令可以形象化的查看你的数据,是数据科学家工作的重要部分。你将频繁地在数据集中发现值得进一步检查的惊喜。
3.4 创建你的模型
你将使用scikit-learn
库来创建你的模型。当编码的时候,这个库被写作sklearn
,正如你即将看见的同样代码。scikit-learn
无疑是最受欢迎的库,用于创建典型的存储于DataFrame
类型的数据模型。
模型的创建和使用步骤:
- 定义
Define
:是一个什么类型的模型?决策树?其他类型的模型?其他特定参数的模型? - 拟合
Fit
:从提供的数据中捕捉模式。这是建模的关键。 - 预测
Predict
:即预测 - 评估
Evaluate
:判断模型预测是否准确
下面是一个例子,用scikit-learn
定义的决策树,然后使用特征和目标变量去拟合。
from sklearn.tree import DecisionTreeRegressor
#Define model.Specify a number for random_state to ensure same results each run
melbourne_model = DecisionTreeRegressor(random_state=1)
#fit model
melbourne_model.fit(X,y)
DecisionTreeRegressor(random_state=1)
许多机器学习模型在训练模型时允许一些随机性。设置一个数字给random_state
确保你每一次运行得到相同的结果。这被当作是一个好的习惯。你使用任何数字,并且模型质量不会完全意义上地依赖你所选择的值。
现在我们拟合了一个模型,可以用来进行预测。
事实上,你想要预测市场上新房屋的价格,而不是已经有了价格的房屋。但是,我们对前几行的训练数据进行预测,来看看预测函数怎么工作的。
print("Making predictions for the following 5 houses:")
print(X.head())
print("The predictions are")
print(melbourne_model.predict(X.head()))
Making predictions for the following 5 houses:
Rooms Bathroom Landsize Lattitude Longtitude
1 2 1.0 156.0 -37.8079 144.9934
2 3 2.0 134.0 -37.8093 144.9944
4 4 1.0 120.0 -37.8072 144.9941
6 3 2.0 245.0 -37.8024 144.9993
7 2 1.0 256.0 -37.8060 144.9954
The predictions are
[1035000. 1465000. 1600000. 1876000. 1636000.]
4.模型评估
你已经建立一个模型。但是模型好不好呢?
在本节课上,你将学习使用模型评估来测量你的模型质量。测量模型质量是不断迭代改进模型的关键。
4.1 什么是模型评估
你想要评价每一个你曾经创建的模型。在大多数(尽管不是所有)情况下,最有意义的模型质量测量是预测准确度。换句话说,就是模型预测结果是否与实际发生的一致。
大多数人在测量预测准确度的时候犯了一个大大的错误。他们用训练数据training data
来做预测,并且将这些预测结果与训练数据的目标值做比较。稍后你将看到用这种方法带来的问题以及如何解决该问题,但是让我们思考一下第一步怎么做。
首先,你需要将模型质量概括成容易理解的方式。如果你比较10000个房屋的预测值和实际值,你可能发现其中混合了好的预测和差的预测。通过一个列表查看10000个房屋的预测值和实际值可能没有意义,我们需要将其概括到一个评估指标single metric
。
有许多概括模型质量的指标,但是我们从一个叫做平均绝对误差Mean Absolute Error (MAE)
的指标开始。我们分解该指标,从最后一个词语误差开始,每一个房屋的预测误差:
error = actual - predicted
如上,假如一个房屋价值150000美元,并且你预测它价值100000美元,误差则为50000美元。
通过MAE指标,我们计算每一个误差的绝对值,这样把每一个误差转换成一个正数。然后,我们计算所有绝对误差的平均值。这就是我们测量模型质量的方法。
为了计算MAE,首先我们需要一个模型。如下:
import pandas as pd
# 加载数据
melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv'
melbourne_data = pd.read_csv(melbourne_file_path)
# 处理缺失值
filtered_melbourne_data = melbourne_data.dropna(axis=0)
#选择预测目标和特征
y = filtered_melbourne_data.Price
melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'BuildingArea', 'YearBuilt','Lattitude', 'Longtitude']
X = filtered_melbourne_data[melbourne_features]
from sklearn.tree import DecisionTreeRegressor
# 定义模型
melbourne_model = DecisionTreeRegressor()
# 拟合模型
melbourne_model.fit(X,y)
一旦我们有了模型,我们可以这样计算MAE
,如下:
from sklearn.metrics import mean_absolute_error
predicted_home_prices = melbourne_model.predict(X)
mean_absolute_error(y,predicted_home_prices)
>>> 434.71594577146544
4.2 样本中“In-Sample”得分问题
我们刚才计算的结果可以看作是样本中In-Sample
得分。我们使用了单一的房屋样本来创建和评估模型,这样做有如下不好的因素:
试想一下,在大型房地产市场,门的颜色与房屋价格无关。
然而,你使用样本中的数据来创建模型,样本中所有绿色门的房屋非常昂贵。而模型的作用是找到预测房屋价格的模式,因此,模型将会识别到这个模式,并且模型将一直把有绿色门的房屋预测为高价。
由于这个模式来源于训练数据,模型在训练数据中将显得准确。
但是,当模型遇见新的数据时将无法保持这个模式,因此在实际中模型将显得非常不准确。
由于模型的实际值来自于对新数据的预测,我们测量的是模型在未用于创建模型的数据上的表现。最直接的方法就是在模型创建的过程中排除掉部分数据,然后用这些数据来测试模型在这些新数据上的准确度。这部分数据叫做验证数据validation data
.
4.3 验证数据
scikit-learn
库有一个函数train_test_split
,可以用来将数据分为两块。我们使用其中一块数据作为训练数据拟合模型,并且我们使用另一块数据作为验证数据来计算平均绝对误差MAE
。
下面是代码:
from sklearn.model_selection import train_test_split
#将数据split分为训练数据和验证数据
#split是基于随机数生成器,因此指定一个数值给random_state变量来保证每次运行获得同样的split
train_X,val_X,train_y,val_y = train_test_split(X,y,random_state = 0)
# 定义模型
melbourne_model = DecisionTreeRegressor()
# 拟合模型
melbourne_model.fit(train_X,train_y)
# 从验证数据中获取预测价格
val_predictions = melbourne_model.predict(val_X)
print(mean_absolute_error(val_y,val_predictions))
>>> 263007.8766946417
4.4 对比
你的样本中数据的MAE约为500美元,然而你的样本外数据的MAE超过了250000美元。
这就是一个近乎完全正确的模型和一个无法用于大部分实际预测目标的模型之间的差别。作为一个参考,验证数据中平均的房屋价格为110万美元,因此使用新数据的误差大约是平均房屋价格的四分之一。
5.欠拟合与过度拟合
在本节的结尾,你将理解欠拟合和过度拟合的概念,并且你将能够运用这些方法来让你的模型更准确。
5.1 用不同的模型来实验
现在,你有一个可靠的方法来测量模型的准确度,你可以通过可供选择的模型来实验,并且看看哪一个模型有最优的预测结果。但是,对模型有哪些选择呢?
你可以查看scikit-learn
的帮助文档,决策树有许多选择项(超过很长一段时间你所想到的或者所需要的)。最重要的选择项决定树的深度。回顾该微课程的第一节,一个树的深度,就是一种表示有多少分支进行预测的尺度。与一个浅度树相反。
事实上,一个决策树在顶层和叶片之间有10个分支并不常见。随着决策树变得更深,数据集被切片成只包含少量房屋的叶片。假如一个决策树仅有一个分支,它将数据分成了两组,假如每一组继续拆分,我们将得到4个组,再次继续拆分,又将得到8个组。如果我们继续通过在每一级添加分支使分组翻倍,我们将得到210 组,也就是第十级,一共1024个叶片。
当我们将房屋分类在许多叶片中,同样的,我们就只有少量房屋分布在每一个叶片中。叶片中只有少量的房屋将使得预测与那部分房屋的实际价值十分接近,但是这样可能导致对新房屋的预测变得不可靠(因为每一次预测都基于仅有的少量房屋)。
这种现象叫做过度拟合overfitting
,就是当一个模型与训练数据完美的匹配,而在模型验证和其他新数据上表现很差。反过来说,如果我们让决策树变得很浅,模型就不能将房屋分成非常明确的组。
极端条件下,如果一个决策树将房屋仅仅分为2组或4组,每一组仍然有大量不同种类的房屋。甚至在训练数据中导致预测结果与大部分房屋不同(并且由于同样的原因,它也将在模型验证中表现很差)。当一个模型从数据中不能够捕捉重要的差别和模式,甚至在训练数据中表现的很差,这种现象叫做欠拟合underfitting
.
因此我们关注模型在新数据上的准确度,通过验证数据来估计,并且想要找到欠拟合和过度拟合之间的甜点sweet spot
。形象地如下图所示,我们想要获得红色的验证曲线的最低点:
5.2 一个例子
有许多可供选择的方式来控制决策树的深度,并且许多方式允许某些路径有更深的深度。但是,最大叶片节点max_leaf_nodes
参数提供一个非常灵敏的方式来控制欠拟合vs过度拟合。我们允许模型的叶片越多,我们在图像上从欠拟合区域到过度拟合的区域移动的越多。
我们可以使用效用函数来帮助比较不同最大叶片节点值的MAE
分数:
from sklearn.metrics import mean_absolute_error
from sklearn.tree import DecisionTreeRegressor
def get_mae(max_leaf_nodes,train_X,val_X,train_y,val_y):
model = DecisionTreeRegressor(max_leaf_nodes=max_leaf_nodes,random_state=0)
model.fit(train_X,train_y)
preds_val = model.predict(val_X)
mae = mean_absolute_error(val_y,preds_val)
return(mae)
使用的是之前小节写过的代码将数据载入train_X, val_X, train_y 和 val_y 。
# Data Loading Code Runs At This Point
import pandas as pd
# Load data
melbourne_file_path = '../input/melbourne-housing-snapshot/melb_data.csv'
melbourne_data = pd.read_csv(melbourne_file_path)
# Filter rows with missing values
filtered_melbourne_data = melbourne_data.dropna(axis=0)
# Choose target and features
y = filtered_melbourne_data.Price
melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'BuildingArea',
'YearBuilt', 'Lattitude', 'Longtitude']
X = filtered_melbourne_data[melbourne_features]
from sklearn.model_selection import train_test_split
# split data into training and validation data, for both features and target
train_X, val_X, train_y, val_y = train_test_split(X, y,random_state = 0)
我们可以使用一个for
循环来比较不同最大叶片节点值建立的模型的准确度。
#compare MAE with differing values of max_leaf_nodes
for max_leaf_nodes in [5,50,500,500]:
my_mae = get_mae(max_leaf_nodes,train_X,val_X,train_y,val_y)
print("Max leaf nodes: %d \t\t Mean Absolute Error: %D" %(max_leaf_nodes,my_mae))
Max leaf nodes: 5 Mean Absolute Error: 347380
Max leaf nodes: 50 Mean Absolute Error: 258171
Max leaf nodes: 500 Mean Absolute Error: 243495
Max leaf nodes: 5000 Mean Absolute Error: 254983
如上面列表所示,500是叶片的最优值。
5.3 小结
本节要点!模型可能遇到的麻烦:
- 过度拟合:捕捉到错误的模式在未来不会出现,导致预测准确度低,或者
- 欠拟合:未能捕捉到相关的模式,同样导致预测准确度低。
我们使用验证validation
数据,该数据未用于模型训练,来测量一个候选模型的准确度。因此让我们尝试更多的候选模型,然后选择最优的。
6.随机森林
6.1 简介
决策树留给你一个艰难的决策。由于每一次预测都来自分支上少量的住房历史数据,因此有着许多分支的深度树容易过度拟合。但是,只有少量分支的浅度树由于不能够从原始数据中提取样本差异,也不能够很好的拟合模型。
甚至当前最先进的建模技术也会面对欠拟合和过度拟合的矛盾。然而,许多模型有很好的方法更好的拟合模型,以随机森林(random forest)为例。
随机森林使用许多分支,并且通过平均每一个组成分支的预测结果来做预测。通常比单一决策树有更好的预测精度,并且使用默认参数运行良好。假如你持续建模,你可以了解到更多表现更好的模型,但许多模型对于取得正确的参数较为敏感。
6.2 举例
在上一章的结尾加载的数据,有如下的变量:
- train_X
- val_X
- train_y
- val_y
用相似的方法建一个随机森林模型,使用RandomForestRegressor
来替代DecisionTreeRegressor
。
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
forest_model = RandomForestRegressor(random_state=1)
forest_model.fit(train_X,train_y)
melb_preds = forest_model.predict(val_X)
print(mean_absolute_error(val_y,melb_preds))
>>> 191669.7536453626
6.3 总结
可能还有提升模型的空间。但是,这是一个很大的提升对于最优决策树250000的误差来说。类似于改变单一决策树的深度,随机森林可以通过调节参数来改变模型表现。此外,随机森林的一个优秀特点是,即便在没有调优的情况下,通常都能正常运行。
7.机器学习竞赛
参加机器学习竞赛是提升你的数据科学技能和测量你的进步的优秀方法。
在接下来的练习中,你将创建和提交为kaggle学习用户设置的房屋价格竞赛。