Press "Enter" to skip to content

使用机器学习实现奇偶分类

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

由于后续主要使用机器学习进行流量识别、指纹识别,因此这里主要聚焦于分类问题。

 

假定背景:对任意给定的数根据奇偶性进行分类。

 

步骤

 

大部分情况下,使用机器学习进行分类工作,主要包含以下步骤:

 

 

    1. 收集数据

 

    1. 读入数据

 

    1. 预处理数据(清除无效数据、数据类型调整、选取特征值)

 

    1. 将数据分为训练集和测试集

 

    1. 使用特定参数的模型对训练集进行训练

 

    1. 使用测试集对训练好的模型进行测试

 

    1. 调整特征、参数,重复上述工作

 

 

实验过程

 

第一次实验

 

由于这里只是对整数进行奇偶性判断,因此数据使用生成的随机数即可

 

import pandas as pd
import random
def g():
    i = random.randint(0,999999)
    return [i, i%2]
data = pd.DataFrame([g() for i in range(100000)])

 

上述代码将会生成长度为 100000 的列表,并且每个元素都包含随机数与其奇偶性(0 为偶数,1 为奇数)

 

列表将会被转换成 pandas 的 DataFrame
类型,以便于后续处理

 

在 Jupyter Notebook 中,可以使用 data.head()
对数据进行预览(如果不填写参数,默认只显示前 5 个)

 

 

0 1
0 319255 1
1 430655 1
2 286442 0
3 709373 1
4 589398 0

 

这里不存在缺失值,因此暂时不做其他额外处理,只将特征和标签分离即可。

 

对于 pandas.DataFrame
,只需要使用中括号即可直接取一列数据。在机器学习中,特征使用 X
(大写)表示,每一行是一组数据,可能包含多列特征值;标签使用 y
表示,行数和特征行数相同,表示该数据对应的类型。

 

在这里,特征和标签都只有一列,分别使用 x
y
表示。由于前面提到,特征往往存在多列,因此后续模型遍历也会认为 x 是一个二维数组。对于一列的数据,在后续操作中无法直接对其训练。在这里使用 numpy 的 reshape()
来将一维数组转换为二维数组,以便于后续操作。

 

x = data[0].to_numpy().reshape(-1, 1)
y = data[1]

 

如果使用 Jupyter Notebook,可以使用单独的两个块输出下 x
y
的值进行再次确认。

 

接下来则是将数据分为训练集和测试集,使用 sklearn 的 train_test_split
可以按照要求分割训练集和测试集。通过设置 test_size=0.3
来将 30% 的数据用于测试,70% 的数据用于训练。同时这里的分割将会乱序分割,以避免数据顺序导致模型训练出现偏差。

 

from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x,y, test_size=0.3)

 

模型拟选用 K-
与 随机森林
两种。这里仅使用相应算法,不需要考虑具体实现,当作黑盒使用即可。

 

首先是 K-近邻 分类器(KNeighborsClassifier)

 

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(x_train, y_train)
knn.score(x_test, y_test)

 

接下来是 随机森林 分类器(RandomForestClassifier)

 

from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier()                     
rfc.fit(x_train,y_train)                     
rfc.score(x_test,y_test)

 

可以发现两个算法只有大概 50% 准确率,约等于瞎猜。

 

以 K-近邻 为例,其算法实际上基于特征之间的距离。将多维度特征映射至高维空间,将距离较近的数据分类到一起。而显然对于一维数轴,奇偶性和距离没有任何关系。因此对于这些训练器几乎无法得到一个较好的结果。

 

那幺如何对其进行分类呢?

 

第二次实验

 

如果采用人脑思维进行奇偶性判断,我们实际上只需要注重于最后一位的奇偶性,或者说二进制下的最后一位就是奇偶性。那幺在特征提取中,应该尝试将每位的数提取出来作为特征。而非整体作为特征。

 

def g():
    i = random.randint(0,999999)
    return list(map(int, list("%010d"%i))) + [i%2]

 

对上面的 g()
进行修改,先使用格式化输出将高位用 0 补全到 10 位(必须保证所有数特征个数相同),然后将其分割成单个数字并整合为整数特征。

 

如下,是新的数据集(最后一列为标签)

 

 

0 1 2 3 4 5 6 7 8 9 10
0 0 0 0 0 8 5 1 1 9 1 1
1 0 0 0 0 8 5 3 9 1 1 1
2 0 0 0 0 6 0 9 2 6 0 0
3 0 0 0 0 4 7 8 7 2 8 0
4 0 0 0 0 0 0 8 1 2 5 1

 

由于这次特征不是单维,因此只需要将前 10 列提取即可

 

x = data.iloc[:,:10]
y = data[10]

 

后续代码无需更改,再次执行,即可发现 K-近邻 准确率达到 75% 左右,随机森林 准确率达到 99%。

 

那幺这就完成了幺?从原理上来说,K-近邻 在解决该问题上确实存在缺陷,但是准确率达到 99% 的随机森林应该是可以做到 100% 的。

 

尝试修改模型参数

 

rfc = RandomForestClassifier(
    n_estimators=81,
    max_features=6, 
    oob_score=True,
    random_state=10,
)

 

再次执行即可得到 100% 的准确率。

 

简单总结

 

对于更为复杂的数据和场景,将会需要更为精妙的方式来提取特征,甚至需要对特征的不同项进行加减操作。同时对于某些模型,要求对数据进行 归一化处理
(数据除以该列最大值,得到一个 0~1 的浮点数)

 

看似机器学习可以是由机器进行分类,但实际上除去打标签部分需要手动操作,如何提取特征也需要人进行参与。对特征进行提取需要需要对数据具有深刻理解,甚至在某些情况下与自己手动分类所花费的工作量差别并不太大。

 

完整代码

 

# To add a new cell, type '# %%'
# To add a new markdown cell, type '# %% [markdown]'
# %% [markdown]
# # 奇偶性判断
#
# 使用随机数生成数据,并判断数据奇偶性
# %% [markdown]
# ## 读入数据
#
# %%
import pandas as pd
import random
def g():
    i = random.randint(0,999999)
    # return [i, i%2]
    return list(map(int, list("%010d"%i))) + [i%2]
data = pd.DataFrame([g() for i in range(100000)])

# %%
data.head()
# %% [markdown]
# ## 预处理数据
#
# 将特征和标签分离
# %%
# x = data[0].to_numpy().reshape(-1, 1)
# y = data[1]
x = data.iloc[:,:10]
y = data[10]

# %%
x
# %% [markdown]
# ## 分离训练集和测试集
#
# 按照 7:3 的比例分割
# %%
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x,y, test_size=0.3)
print(x_train)
# %% [markdown]
# ## 训练并测试模型
#
# 分别使用 K-近邻 和 随机森林 算法
# %%
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(x_train, y_train)
knn.score(x_test, y_test)

# %%
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier(n_estimators=81,max_features=6, oob_score=True,random_state=10)                     
rfc.fit(x_train,y_train)                     
rfc.score(x_test,y_test)

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注