机器学习实战 2.3获取数据

2.3.2 下载数据

 

我本来放在了这个位置:

即书上提供的github网址上直接下载的code包粘贴到了我的study文件夹。但后来还是换成了一下位置(直接在D盘),原因后续会提到:

注意在jupyter里面不要开启pytorch环境,因为我那里面还没pandas库:

按文章输入代码:

 这里因为下载解压了数据文件,所以本地下载。当然没,没有按照书上的方法 选择此方法的最大原因是总是报错“URLError: <urlopen error [Errno 11004] getaddrinfo failed>”,经过搜搜发现是网络问题。将适配器ipv4的DNS修改为“114.114.114.114”、“8.8.8.8”、“8.8.4.4”等等都没有得到解决。打算连接vpn,却不知为何toline无法启动,遂作罢。

2.3.3 快速查看数据结构

1、查看前五行

 2、获取数据集的简单描述

3、对object类型的属性ocean_proximity感兴趣,猜测是一个分类属性。想知道有多少种分类值:

 4、显示数值属性的摘要:

使用 describe() 获取数值属性的描述,注意统计时的空值会被忽略。

5、绘制每个属性的直方图

绘制每个数值的直方图。直方图横轴表示数值范围,纵轴表示实例数量。这些直方图反映出很多问题。见p55页。

2.3.4 创建测试集

一、纯随机抽样 

下面代码是随机选择一些实例创建测试集,选取数据集的20%(数据集越大,这个比例越小)。

但是这样每次运行都会产生一个不同的数据集,这样我的机器就会逐渐窥探到所有数据集,这是测试时不想看到的。

解决方案:每个实例都使用一个标识符,用以决定是否进入测试集。然后,可以计算每个实例这个标识符的哈希值(小于等于最大哈希值的20%就将其放入测试集)。这样的测试集在多个运行里都是一致的了,即使更新了数据集也一样——新的实例中有20%会被放入测试集,并不会将之前的实例放入新的测试集。

实现方式如下:

from zlib import crc32
def test_set_check(identifier, test_ratio):
    return crc32(np.int64(identifier)) & 0xffffffff < test_ratio *2**32
def split_train_test_by_id(data, test_ratio, id_column):
    ids = data[id_column]
    in_test_set = ids.apply(lambda id_: test_set_check(id_, test_ratio))
    return data.loc[~in_test_set], data.loc[in_test_set]

由于housing数据集没有设置标识符列,所以这里我们将行索引作为id:

housing_with_id = housing.reset_index() #adds an 'index' column
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "index")

这有一个条件:确保在数据集的末尾加入新数据而不是插入(不能改变索引值),且不能删除任意一行。如果不能保证这点,那就试着利用万年不变的特征(本例中的经纬度)构造组合成一个id:

housing_with_id["id"] = housing["longitude"]*1000 + housing["latitude"]
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "index")

数据集拆分成多个子集:

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

二、优化的测试集

 经调研可知,收入中位数对于预测房价中位数十分重要。所以在收入这一属性上,我们希望测试集能够代表各种不同类型的收入,即分层抽样。根据直方图中的数值,大多数收入中位数聚集在 [1.5, 6] 之间,划分层次时,每层要有足够多的实例,因此,使用 pd.cut() 方法创建 5 个收入类别, 0-1.5 、 1.5-3 、 3-4.5 、 4.5-6 、 6- +∞ 。

注意:每一层都要保证足够的样本数量,所以层数不应该太多。 

下面是根据pd.cut()创建5个收入类别属性(标签1~5),0~1.5是类别1...类别如输出直方图所示:

housing["income_cat"] = pd.cut(housing["median_income"],
                               bins=[0., 1.5, 3.0, 4.5, 6., np.inf],
                               labels=[1, 2, 3, 4, 5])
# 根据income_cat数据绘制直方图                   
housing["income_cat"].hist()

我们根据 income_cat 列进行分层抽样,再使用 Scikit-learn 的 StratfiedShuffleSplit 类来实现。划分完测试集就可以将 income_cat 列删除。

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(housing, housing["income_cat"]):
    # train_index: [17606 18632 14650 ... 13908 11159 15775]
    strat_train_set = housing.loc[train_index]
    # test_index: [5241 10970 20351 ...  4019 12107  2398]
    strat_test_set = housing.loc[test_index]

首先看一下测试集的收入类别比例分布(从多到少排序):

strat_test_set["income_cat"].value_counts() / len(strat_test_set)

好,现在可以删除income_cat属性,将数据恢复原样了:

for set_ in (strat_train_set, strat_test_set):
    set_.drop("income_cat", axis=1, inplace=True)

这个shift+enter执行一次后就成功删除了。我这里忘记执行连按了两次,报错

KeyError: "['income_cat'] not found in axis

实际上它已经不存在了。除非在jupyter里面从from sklearn.model_selection import StratifiedShuffleSplit这一行开始重新执行回复income_cat再将其删除。

参数说明:

labels 就是要删除的行列的名字,用列表给定
axis 默认为0,指删除行,因此删除columns时要指定axis=1;
index 直接指定要删除的行
columns 直接指定要删除的列
inplace=False,默认该删除操作不改变原数据,而是返回一个执行删除操作后的新dataframe;
inplace=True,则会直接在原数据上进行删除操作,删除后无法返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值