Hash
hash又被称为散列函数
我的理解,hash是一个过程,也被称为预映射,通过事先设计好的算法,将一个任意长度的字符串,通过这个预映射,得到一个长度固定的输出
这个输出有以下几个特点:
- 输入值的值域不固定,但是散列值的值域是固定的
- 对固定的一个输入,有唯一一个输出(称为散列值)
- 一个输出,可能不止对应一个输入,即不同输入可能指向同一个散列值
- 一个输入的很微小的变动, 可能会导致散列值的巨大变化
- 经过hash运算,散列值基本会均匀分布在其值域的各个部分
hash的设计思想
hash的一大作用,就是构造了关键词与其存放的地址(是在hash表中的位置,不是实际的物理地址)的某种关系的映射
如果平时我们要查找数据,可能是遍历一遍数据表,而通过hash表来存储的话,只需输入需要查找的关键词,就能找到对应的数据了(这一点和python中的字典有点像)
可以明显得提升查找的速度
hash碰撞
刚刚说过,不同的输入可能指向同一个散列值,这种情况就成为hash碰撞
常见的处理方法有开放寻址(Open Addressing)法和链接(Chaining)法
具体过程可以自行百度
hash的运用
hash在很多领域都有广泛应用,例如密码学,数据库中存放经过hash运算的密码,就可以防止用户密码被盗(hash运算有不可逆性)
另外就是数据结构,hash表有着较快的查找速度,如果你对速度的要求较高,而且不太重视hash碰撞的话,hash表就比较不错(当然,hash碰撞也有对应的解决方法)
运用hash运算在机器学习中选择测试集
刚刚说到过,hash运算为了充分利用散列值的值域,会将数据尽量均匀地分布在各处
我们可以利用这一特性,将数据的某一特征作为hash运算的关键词,对该特征进行hash运算,然后根据hash运算后的结果,选取一定的比例(通常为20%)作为测试集
这么做的好处
一是可以将数据集打乱,
二是数据集中的训练集和测试集会相对固定,即第二次运行程序时,原本被选为测试集的数据仍为测试集
我们将这种方法与其他方法进行比较:
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]
这个函数的作用是随机选取20%的数据作为测试集
这个做法有效有效但并不完美,因为重新运行时,这个程序会选择不同的测试集,次数多了,你就会获整个数据集
我们可以在程序运行之前这么做,然后保存测试集和训练集,或者,在运行np.random.permutation()
之前,给随机数设置随机数种子,np.random.seed(42)
,这里的42是随意设定的,但是通常我们都用这个
但是,这种方法当数据集变化之后,选择的测试集又会发生变化
所以!!
用hash运算来选择测试集的好处有以下几点:
- 选择的测试集是固定的,不会因为程序的重启而变化
- 可以用于不断变化的数据集,即使数据集重新添加了很多数据,运用hash运算不会改变原本的测试集
以下给出的是用hash实现的对数据集的分割
主要思想就是根据数据的序号进行hash运算,计算出每个实例 ID 的哈希值,只保留其最后一个字节,如果该值小于等于 51(约为 256 的 20%),就将其放入测试集
import hashlib
def test_set_check(identifier, test_ratio, hash):
return hash(np.int64(identifier)).digest()[-1] < 256 * test_ratio
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]
data_with_id = data.reset_index() # adds an `index` column
train_set, test_set = split_train_test_by_id(data_with_id, 0.2, "index")
本文关于Hash选择测试集的代码取自《hands-on-machine-learning》
欢迎友善的交流与指正