导师给的任务是给你一个List,里面填充了各种已经结构化的数据,即每一行是同一个用户的所有维的数据,同一列是不同用户的同一维/同属性的数据,问如何通过机器学习的逆向分析得到每一列的属性类型。
1 问题是什么
首先先来描述一下这个问题是什么意思。首先由用户提供一张ListA(当然可以重复操作,即也可以在计算ListA结束再提交ListB、ListC...),里面有各种数据,如下表格ListA所示。其中,每一行是一个用户各种信息数据(例如姓名、出生日期、性别、电话、邮箱、名族、籍贯、家庭住址等等),维数不一定,也就是说可能只有两三列,也可能有很多很多列;每一列是相同属性的各种数据,其中有可能包含脏数据(比如电话应该是11位的,但是List中会可能出现);注意第一行的Coli行在用户提供的数据List中是不存在的。问题是,根据表ListA中的数据经过机器学习,逆向分析出每一列数据的列名Coli,同时,因为User和Col的数据量很大,尤其是User的数量可以达到几百万、几千万,所以要求注意算法的时间复杂度合理。
无属性列的数据表ListA | |||||||
| Col1 | Col2 | Col3 | ... | Colj | ... | ColN |
User1 | data11 | data12 | data13 | ... | data1j | ... | data1N |
User2 | data21 | data22 | data23 | ... | data2j | ... | data2N |
User3 | data31 | data32 | data33 | ... | data3j | ... | data3N |
User4 | data41 | data42 | data43 | ... | data4j | ... | data4N |
... | ... | ... | ... | ... | ... | ... | ... |
Useri | datai1 | datai2 | datai3 | ... | dataij | ... | dataiN |
... | ... | ... | ... | ... | ... | ... | ... |
UserM | dataM1 | dataM2 | dataM3 | ... | dataMj | ... | dataMN |
2 关键是什么
2.1 如何辨别并且除去脏数据对结果的影响(去噪过程)的同时,控制合理的时间复杂度
我们目前已经知道该ListA中可能存在脏数据,那么为了算法的准确性,我们先假定认为脏数据存在,并且为了表述清晰,任意选取一列j,认为第j个属性的这一列的M个数据中的脏数据个数为B(BadData),当然B在数据M中肯定是占少数的。我们如果想要去掉脏数据对分析结果的影响,那么就需要将测试该j列中尽量多的数据,假设测试数量是K(K相当于是一个测试数量的阀值,当然K是属于0~M的正整数),如果测试数据的个数K越趋近于全部的列数据量M,得到的结果就越准确。
但是考虑到时间复杂的问题就不能这么考虑了,因为如果用户M的数据量达到了几百万几千万,那么遍历一遍确认一个属性所花费的时间代价将十分的大,更不要说每个用户数据都有有很多维数了。所以,必须考虑选取适当的K值,使得在每一列的计算中,既不会影响到最终算法的准确性,也可以控制在合理的时间复杂度内。
2.2 对相似数据的区分处理(即相似数据分割)
我对老师传过来的一些范例的EXCEL表数据进行了观察,发现很多表中除了姓名和住址信息是填写的汉子数据,其他的数据都是按照字典规范填写的相应的数值。比如说电话号码11位数字、身份证号码18位数字(最后一位可以是X)、省市地区代码3位、民族代码2位,性别1位数字、已婚未婚1位数字,等等。那么一张表格里面都是数字,数字之间就会有干扰,这就为如何通过逆向分析来判断出哪个数据对应着哪个列制造了很大难度。
3 方案是什么
3.1 对整体数据进行正则表达式处理方法的说明
我通过搜索资料发现,通过正则表达式来处理字符串、表单的技术已经十分成熟,那么我就可以利用已经存在的常用的正则表达式来查找验证表中的中文字符、数字字符、字母字符、邮箱网址的 特殊字符,然后再利用函数返回每个数据单元dataij的长度,和已有的特征进行比较,那么就可以基本的判断出该dataij是属于哪种数据了。
提一下,常用的正则表达式已经整理收藏,揭露在笔者CSDN的《正则表达式的 使用(2)__常用的正则表达式(积累)》,里面记录了正则表达式常用的 一些匹配指定字段的公式,屯下来方便以后参考和使用。
3.2 针对“如何辨别并且去噪脏数据的同时,控制合理的时间复杂度”的解决方案
去噪脏数据的问题其实在问题提出的时候已经说了怎么解决了,就是提高数据采集量,通过概率学的理论来减小甚至扼杀脏数据对最终结果的影响。那么现在主要讨论的问题就是这个K值该如何选取。为了讲清楚这个问题,我们举一个简单的例子。
假如说我们现在分析的这一列是电话号码,现在有1000个数据,即M=1000,其中脏数据有6个(比如输入的号码不是11位,或者用正则表达式检测出输入的数字中夹杂有字母,或者什么其他问题),现在用random的方式选取这1000个数据的数据,一个个的加,即K值从K=1开始逐渐增大,我们来看一下它匹配成功的到电话号码这一选项的概率随着数量增加的变化。如下表格所示。
(注:为了验证正确性以及方便运算演示,我们假设一种最坑爹的状况,即一开始选取的6个数据均是脏数据)
基于控制时间复杂度的阀值选取实验(实验目标列:电话号码) | |||||||
参数注释——K值(random选取的测试数据的个数) | |||||||
参数注释——成功匹配上电话号码选项的概率 | |||||||
K | P | ... | K | P | ... | K | P |
1 | 0.000 | ... | 236 | 0.975 | ... | 981 | 0.994 |
2 | 0.000 | ... | 237 | 0.975 | ... | 982 | 0.994 |
3 | 0.000 | ... | 238 | 0.975 | ... | 983 | 0.994 |
4 | 0.000 | ... | 239 | 0.975 | ... | 984 | 0.994 |
5 | 0.000 | ... | 240 | 0.975 | ... | 985 | 0.994 |
6 | 0.000 | ... | 241 | 0.975 | ... | 986 | 0.994 |
7 | 0.142 | ... | 242 | 0.975 | ... | 987 | 0.994 |
8 | 0.250 | ... | 243 | 0.975 | ... | 988 | 0.994 |
9 | 0.333 | ... | 244 | 0.975 | ... | 989 | 0.994 |
10 | 0.400 | ... | 245 | 0.976 | ... | 990 | 0.994 |
11 | 0.455 | ... | 246 | 0.976 | ... | 991 | 0.994 |
12 | 0.500 | ... | 247 | 0.976 | ... | 992 | 0.994 |
13 | 0.538 | ... | 248 | 0.976 | ... | 993 | 0.994 |
14 | 0.571 | ... | 249 | 0.976 | ... | 994 | 0.994 |
15 | 0.600 | ... | 250 | 0.976 | ... | 995 | 0.994 |
16 | 0.625 | ... | 251 | 0.976 | ... | 996 | 0.994 |
17 | 0.647 | ... | 252 | 0.976 | ... | 997 | 0.994 |
18 | 0.667 | ... | 253 | 0.976 | ... | 998 | 0.994 |
19 | 0.684 | ... | 254 | 0.976 | ... | 999 | 0.994 |
20 | 0.700 | ... | 255 | 0.976 | ... | 1000 | 0.994 |
从上表的数据中,我们可以看到,在一开始的时候,概率P随着选取个数K值的增加而迅速改变,但是慢慢的增长速度急剧减小,最终增长速度十分缓慢甚至趋于平缓不增。那么这就为我们适当的选取K值,从而减少每一列测试的数据量,控制时间复杂度提供了条件和可能。那么,该如何选取这个K值呢?
这里我想到了以前做机器人视觉处理系统时候,分割图像的目标物体而采用的阀值化处理的经验,我觉得,可以找到一个合理的阀值TH(Threshold--阀值的意思),当K等于阀值TH的时候,既能满足精确度需要,又能控制算法运行时间。当然这也可以用函数图像做更加生动的解释。我们首先来观察一下上面表格的数据,通过分析我们发现,如果将上述表格的数据作为参数建立二维坐标系,其中用K值作为X轴,用P作为Y轴,那么我们得到了应该是一条形状类似log函数的曲线,该曲线随着X的增大而趋于一个稳定值,如下图所示。(电脑里没安装Matlaba,先拿画板凑活了 = =)
如图中所示的一样,既然随着X的增大会越来越趋于缓和,那么找到某一个恰当位置的阀值TH,使得X=TH,我们就可以达到既满足算法结果的精确度又控制算法时间的效果(节约的算法时间主要是X>TH的部分,这相当于剪枝)。
那么现在的关键就是计算TH值了。我设计的计算TH的步骤如下:
(1)建立数学模型,计算这个数学模型中的概率P,计算方法是:
(其中P为概率,X为选取的K值,B为已经被选中测试的脏数据数量)
(2)计算概率的增长率,计算方法是:
(3)然后我们就可以设定精度了,如果我将精度设置为万分之一,也就是当概率的增长率小于我的预定的精度时,我们认为此时概率的增长已经十分缓慢,甚至近乎稳定了,那么后面就可以不再选取数据继续测试,以控制时间复杂度。计算过程如下:
(4)总结与验证
经过上面的计算,我们已经得到了阀值TH=245(针对本案例的数学模型),这表明:当我们选取的数据个数大于245个时,我们可以保证计算的结果较为准确,并且因为只计算了所有数据的一部分,因此大大的节约了计算时间。那么,当我们进行匹配时,我们只需要随机在1000个数据中选取245个,与各个数据列的特征集合进行比较,就可以快速准确的找到该列数据的分类了。
我们可以将这个计算结果对照刚才采集的数据表表格进行比较,我们可以看出来,在K=245的时候(表格中数据已经加黑涂黄),前后的数据已经比较的稳定,概率的增长很慢了,所以可以有效的代表最终的分类结果。
3.3 针对“对相似数据的区分处理(即相似数据分割)”的解决方案
3.3.1 考虑长度不同的数据之间的关系如何分割
1、应为每一个单元格的数据可以认为是string的或者char[ ]的,那么采用length的方式提取相应的长度,然后根据比较该数据列的数据长度与集合的各个属性列的长度特征比较的结果,就可以对数据进行分类。
比如:11位的电话号码、18位的身份证号码、省市地区代码3位、民族代码2位、性别1位、已婚未婚1位,等等
3.3.2 考虑长度相同的数据之间的关系如何分割
这个情况十分的恶心,目前只有想到的几种方法可以提高分割精度,但并不是绝对准确,有待继续思考研究。
1、根据数据项固有特征进行分割
比如性别和已婚未婚都是长度为1的数据,但是考虑到这是浪潮合作的企业的员工信息,那么作为成年人,年龄段在22岁~60岁不等,结婚率普遍应该在7成左右,与此形成鲜明对比的是男女比例应该是稳定在0.55左右(这个可以查阅中国人口普查相关网站,调阅2000~2014十五年男女比例的普查结果得到),因此我们可以根据整列的数据项的分布律对数据列进行划分归类。
2、根据历史数据进行预测分析
其实这里是应用的大数据思想,大数据思想的本质就是依靠过往的历史数据对未来或当前的事情进行分析预测。那么我想,或许我们可以模仿英文字母使用频率的经典案例(我们都知道,A~Z这26个字母在英文单词中的使用率是不相同的,这也导致了哈夫曼树的诞生以及哈弗曼编码规范的产生,大大提高了编码效率),也给属性列集合的各个属性列加上权值,使其进入最后的结果计算,从而对分析结果产生一定的矫正作用。
例如:我们一般在填表格中,假设出现性别一栏的概率是0.91,而出现已婚未婚一栏的概率是0.77,那么就用Probability(性别)*0.91与Probability(已婚未婚)*0.77做比较,从而决定这一列到底是哪种属性列。
------------------------------------------------------------------------------------------------------------------------------------------
目前这些只是些初步想法,具体的细节有待仔细考虑,进行改进。
同时欢迎大家提出想法,共同讨论。如有不正确之处,欢迎指教!