加州房价预测项目详细笔记(Regression)——(2)采样(数据分割)<重要>

参考内容:

《机器学习实战》原作者github:https://github.com/ageron/handson-ml

加州房价预测项目精细解释https://blog.csdn.net/jiaoyangwm/article/details/81671084

DataFrame.where:

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.where.html

快速学会pandas中Dataframe索引.ix,.iloc,.loc的使用以及区别https://blog.csdn.net/qq1483661204/article/details/77587881


为了防止数据窥探偏误(data snooping bias),一般会将机器学习的数据集划分成三个子集:训练集,验证集测试集

训练集是用来训练模型的,给模型输入和对应的输出,让模型学习它们之间的关系。

验证集是用来估计模型的训练水平,比如分类器的分类精确度,预测的误差等,我们可以根据验证集的表现来选择最好的模型。

测试集是输入数据在最终得到的模型得到的结果,是训练好的模型在模拟的“新”输入数据上得到的输出。(只能在最后用于测试模型的性能,不能拿来训练。)

常见的划分比例是:50%用于训练,25%用于验证,25%用于测试。(或60%、20%、20%),这个比例可以根据数据集的大小和数据信噪比来改变。 


一、纯随机抽样创建测试集

该项目只分成训练集和测试集两个部分,选取20%的数据作为测试集。

(1)简单划分

通过创建split_train_test函数,实现将数据集分成训练集和测试集两个部分的目标:

import numpy as np
def split_train_test(data, test_ratio):
    shuffled_indices = np.random.permutation(len(data))
    test_set_size = int(len(data) * test_ratio)
    test_indices = shuffled_indices[:test_set_size]
    train_indices =shuffled_indices[test_set_size:]
    return data.iloc[train_indices], data.iloc[test_indices]
    
train_set,test_set = split_train_test(housing,0.2)
print(f"{len(train_set)} train + {len(test_set)} test")
# print(len(train_set), "train +", len(test_set), "test")

但是这样简单的划分数据集的话,每运行一次可能会产生不同的训练集和测试集。运行次数多的话,可能整个数据集都被运用,没能起到测试集的作用。

解决方案:

1) 在第一次运行程序后就保存数据集,后面的运行只是加载它;

2)为了保证在下一次获得更新的数据时不会中断,常见的解决方法是每个实例都使用一个标识符(identifier)来决定是否进入测试集;

3)通过Scikit-Learn提供的函数train_test_split的random_state参数,设置一个随机数生成器的种子,从而让它始终生成相同的随机索引。例:random_state = 42;42出自《银河系搭车客指南》的“关于生命、宇宙和一切的终极问题的答案”。

(2)使用标识符(identifier)划分

  • 使用行号索引

housing数据集没有标识符列,最简单的是使用行号索引作为ID:

housing_with_id = housing.reset_index() #新增一个“index”列
train_set, test_set = split_tain_test_by_id(housing_with_id, 0.2, "index")

使用这种方法需要确保在数据集的末尾添加新数据,并不会删除任何行。

  • 创建稳定的标识符

如果没法保证使用行索引使用要求的话,可以尝试使用一个最稳定的特征来创建唯一标识符(本例选择经纬度)

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

(3)使用Scikit-Learn提供的函数train_test_split

通过Scikit-Learn提供的函数train_test_split的random_state参数,设置一个随机数生成器的种子,从而让它始终生成相同的随机索引。

from sklearn.model_selection import train_test_split
train_set,test_set = train_test_split(housing, test_size = 0.2, random_state = 42)
print(f"{len(train_set)} train + {len(test_set)} test")

纯随机的取样方法在数据集很大的时候(尤其是相较于属性的数量而言),通常是可行的。但是如果数据集不大,可能会导致明显的抽样偏差。


二、分层抽样创建测试集

数据少的时候采用分层抽样,从每个分层去取合适数量的实例,能相对保证测试集对总人数具有代表性。

专家建议收入中位数(median_income)是一个非常重要的属性,因此可以以这一属性作为分层抽样的依据。(随机切分会将原本的数据分布破坏掉,比如收入、性别等,保证特性分布是很重要的)

(1)以中位数(median_income)创建一个分类属性

  • 观察收入中位数的柱状图
housing["median_income"].hist()
plt.show()

可以看到,收入中位数(median_income)集中在2~5(万美元)附近,超出6(万美元)的数据较少,为了保证分层抽样的每一层有足够的数据,层数不应该分的太多。

  • 创建分类属性
import numpy as np
housing["income_cat"] = np.ceil(housing["median_income"] / 1.5)
housing["income_cat"].where(housing["income_cat"] < 5, 5.0, inplace = True)
housing["income_cat"].hist()
plt.show()

这里通过将收入中位数(median_income)除以1.5来限制收入类别的数量,然后使用ceil取整得到离散类别,最后将所有大于5的类别合并成一个类别5。

DataFrame.where()的用法:

DataFrame.where(condition, other, inplace=False, axis=None, level=None, errors='raise', try_cast=<no_default>)


inplace = True 的参数解读:

inplace = True:不创建新的对象,直接对原始对象进行修改;
inplace = False:对数据进行修改,创建并返回新的对象承载其修改结果。

默认是False,即创建新的对象进行修改,原对象不变。

 (2)进行分层抽样

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"]):
    strat_train_set = housing.loc[train_index]
    strat_test_set = housing.loc[test_index]

housing["income_cat"].value_counts() / len(housing)
#查看住房数根据收入类别的比例分布

DataFrame.loc[]的用法:

DataFrame.loc[] 通过轴标签选择数据

DataFrame.iloc[] 通过整数索引选择数据


 n_splits = n的用法:

表示划分为几块(至少是2)   例:n_splits = 1 表示分成两块


三、分层抽样与纯随机抽样的抽样偏差比较

def income_cat_proportions(data):
    return data["income_cat"].value_counts() / len(data)

train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)
compare_props = pd.DataFrame({"Overall": income_cat_proportions(housing),
                           "Stratified": income_cat_proportions(strat_test_set),
                           "Random": income_cat_proportions(test_set),}).sort_index()
compare_props["Rand. %error"] = 100 * compare_props["Random"] / compare_props["Overall"] - 100
compare_props["Strat. %error"] = 100 * compare_props["Random"] / compare_props["Overall"] - 100
compare_props

由图中可以看出,分层抽样测试集的收入分类比例与总数据集的几乎相同,而随机采样数据集偏差严重。


恢复原始数据

删除income_cat这一属性:

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

axis=0:在第一维操作
axis=1:在第二维操作
axis=-1:在最后一维操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值