机器学习实战:各种测试集的划分方法(随机划分,分层抽样,hash划分)

理论上,创建测试集非常简单:只需要随机选择一些实例,通常是数据集的20%。

纯随机的抽样方法

def split_train_test(data, test_ratio):
	# 对0-len(data)之间的序列进行随机排序
    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:]
    #当数据类型为DataFrame时,当需要提取指定位置的元素,就需要用到iloc方法。
    return data.iloc[train_indices], data.iloc[test_indices]

问题1:
但这并不完美:如果再运行一遍,它又会产生一个不同的数据集!

解决方案
在第一次运行程序后即保存测试集,随后的运行只是加载它而已。
另一种方法就是在调用np.random.permutation()之前设置一个随机数生成器的种子

np.random.seed(42)

从而让它始终生成相同的随机索引

问题2
但是这两种解决方案在下一次获取更新的数据时都会中断。

解决方法
每个实例都使用一个标识符(identifier)来决定是否进入测试集(假设每个实例都有一个唯一且不变的标识符)。
可以计算每个实例标识符的hash值,只取hash的最后一个字节,如果该值小于等于61(约256的20%),即便更新数据集也仍然一致。
知识点:

  1. hash().digest()返回bytes格式的消息摘要
  2. hashlib.md5会生成一串十六进制字符串
  3. hash会随机的生成,每次生成的值都不一样,而md5只要里面传的参数是固定的,那么值也就是固定的
  4. apply函数是pandas里面所有函数中自由度最高的函数。该函数如下:
    DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)
    该函数最有用的是第一个参数,这个参数是函数,相当于C/C++的函数指针。apply函数 会自动遍历每一行DataFrame的数据,最后将所有结果组合成一个Series数据结构并返回。
import hashlib

def test_set_check(identifier, test_ratio, hash):
    return hash(np.int64(identifier)).digest()[-1] < 256 * test_ratio
# id_column是标识符列
def split_train_test_by_id(data, test_ratio, id_column, hash=hashlib.md5):
    ids = data[id_column]
    in_test_set = ids.apply(lambda id_: test_set_check(id_, test_ratio, hash))
    return data.loc[~in_test_set], data.loc[in_test_set] # 返回训练集  测试集

Scikit-Learn提供了一些函数,可以通过多种方式将数据集分成多个子集。

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(限制收入类别的数量),然后使用ceil进行取整(得到离散类别),最后将所有大于5的类别合并为类别5

housing["income_cat"] = np.ceil(housing["median_income"] / 1.5)
housing["income_cat"].where(housing["income_cat"] < 5, 5.0, inplace=True)

通过StratifiedShuffleSplit类

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]

知识点:

  1. Series.where(cond, other=nan, inplace=False, axis=None, level=None, errors=‘raise’, try_cast=False, raise_on_error=None)
    如果 cond 为真,保持原来的值,否则替换为other, inplace为真则表示在原数据上操作,为False表明在原数据的copy上操作。

  2. ceil进行取整(得到离散类别)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

evil心安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值