理论上,创建测试集非常简单:只需要随机选择一些实例,通常是数据集的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%),即便更新数据集也仍然一致。
知识点:
- hash().digest()返回bytes格式的消息摘要
- hashlib.md5会生成一串十六进制字符串
- hash会随机的生成,每次生成的值都不一样,而md5只要里面传的参数是固定的,那么值也就是固定的
- 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]
知识点:
-
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上操作。 -
ceil进行取整(得到离散类别)