首先强调一下,本篇博客是我实验得出来的结论,要是错了,可以在评论区指正,嘻嘻
接下来我会介绍以下三个内容
- 为什么要用onehot
- 怎么用
为什么要用onehot:
假设你有一个这样的数据集,格式是csv或者arff格式:
体重 | 身高 | ... | class |
胖 | 1 5 0 | ... | 不好看 |
瘦 | 1 6 0 | ... | 还可以 |
有点胖 | 1 8 0 | ... | 帅 |
有点瘦 | 1 5 0 | ... | 还可以 |
你现在需要对这个数据构建一个分类器,挖掘一些有用的信息,此时你想到了sklearn(真是个错误的决定),你会发现如果你把这个数据集直接当成数据矩阵numpy,输入sklearn中的分类器中,编译器会提示你,类型错误,无法把string(或者btype)类型转成float....
经过我查阅多方资料,我才明白,原来sklearn中的数据默认得是全数值类型。一个非常好又不方便的设定,好在:统一数据类型,不方便在:有得时候我们的数据就是数值,离散值,string类型混合的。那我们就来解决吧(当然,如果你换weka(java)这个机器学习库就没有这种奇怪的问题)
怎么用:
在讲怎么写onehot代码之前,我先简单介绍一下onehot方法,简单地说,onehot方法可以把刚刚上面的这个数据变成这个样子:
是否胖 | 是否瘦 | 是否有点胖 | 是否有点瘦 | 身高 | ... | class |
1 | 0 | 0 | 0 | 1 5 0 | ... | 不好看 |
0 | 1 | 0 | 0 | 1 6 0 | ... | 还可以 |
0 | 0 | 1 | 0 | 1 8 0 | ... | 帅 |
0 | 0 | 0 | 1 | 1 5 0 | ... | 还可以 |
从上面的数据,我们可以发现,onehot方法就是把离散取值(取名词)的属性裂变成多个属性(取值为01),这样就可以给sklearn计算了。
好的,接下来,我展示一下,具体的代码(使用onehot重新编码,并进行knn分类,然后返回十折交叉验证结果的代码)调用示例:
def do_knn(fea,lab,k):
# sdata=fea+lab
auc=0
#x是个矩阵
#arffdata = imp.fit_transform(arffdata)
#lab.reshape(-1,1).reshape(-1)#?????去掉它的多余括号
flo = [] # 存放数值型属性
str = [] # 存放名词性属性
colmn = fea.shape[1] # 存放列数
raw = fea.shape[0] # 存放行数
strnumber = 0#判断是否存在名词性属性
flonumber=0
for i in range(colmn):
if type(fea[0][i]) == bytes or type(fea[0][i]) == np.bytes_:
str.append(fea[:, i])
strnumber += 1
else:
flo.append(fea[:, i])
flonumber+=1
flo = np.array(flo).T
str = np.array(str).T
features=np.random.rand(1)#之后重新赋值
if strnumber != 0 and flonumber != 0:
enc = OneHotEncoder()
enc.fit(str)
str = enc.transform(str).toarray()
str = np.array(str)
features = np.concatenate((flo, str), 1)
if strnumber==0:
features = flo
if flonumber==0:
enc = OneHotEncoder()
enc.fit(str)
str = enc.transform(str).toarray()
features = np.array(str)
knn = KNeighborsClassifier(n_neighbors=k)
scores = cross_val_score(knn, features, lab, cv=5, scoring='accuracy')
auc=sum(scores)/len(scores)
#print(lab)#似乎是因为btype类型的原因
return auc###auc有时居然是空的
代码片段有点长,那是因为这个方法用起来真的不方便(以前的版本是很方便,只需要一行就能实现,后来sklearn把一个关键的函数去掉了。。)
代码解释说明:这个函数是计算一组数据进行knn分类方法并返回十折交叉验证的平均auc的函数。输入的fea是数据的特征(属性),输入的lab是数据的类别,所以这段代码是对fea进行数值化处理的。
关键的代码是这个:
enc = OneHotEncoder()
enc.fit(str)
str = enc.transform(str).toarray()
features = np.array(str)
首先,创建一个onehotencoder对象(方法),然后让这个方法去学str(把fea的所有非数值类取出来,存放在str中)矩阵中的信息(每个属性的取值有几种),再通过transfrom函数就可以把非数值得矩阵转成纯数值的数据矩阵。
补充说明:
上面的代码中,我先对数据集的属性矩阵进行了一个评定,看看这个数据的属性含不含非数值类型,并把数值型属性和非数值属性分开,最后调用onehot方法把非数值属性的矩阵转成纯数值矩阵,最后再把这两个矩阵拼接,构成数据集的完整属性矩阵features,最后利用这个featurs和lab得到了分类的结果。
我这么做的原因是因为,onehot方法以前的版本是可以选择哪一列需要数值化 的,方法是这样 enc=onehotencoder(categories
_featuires=[1,2]),这样的onehot就可以一行实现一个数据矩阵中的第一列和第二列数值化,真的是很方便,但是,不知道为什么,我这个版本把这种这么好的输入参数去掉了。。。。。。。所以他默认就是全部数值化,这样就会导致,如果你有一个属性是身高,取值有148.2,145.6,170.9等等,那么他就会裂变出 是否148.2,是否145.6.......这么多属性。。。。。所以我才做得这么麻烦。
要是你们知道怎么快速进行onehot方法(可以选择那一列裂变),可以在评论区告诉我呀,感谢感谢
、