由于本人也是在数据挖掘的入门阶段,以下内容仅为个人练习经验和见解,如有不恰当之处,希望能与其他人探讨。
在开始之前先说说要准备或者说要具备的知识:
1、学习过python,不需要什么精通,起码要知道python的基本数据结构和大的框架;
2、了解KNN(K最近邻)算法的基本原理,这里我就不多说了,百度一下就能找到,因为我觉得自己没别人解释的好;
3、对数据挖掘有概念性的了解,起码要知道数据挖掘是要做什么。
给点干货,这里有比较详细的KNN算法的python简单实现,很容易理解:http://blog.csdn.net/zouxy09/article/details/16955347
接下来开始我们的入门练习。
1、获取资源
首先,当然是要先去kaggle上获取相关的资源了,点击这里就能进去kaggle,然后自然就是要先注册了。在这里和大家说一下,注册时如果你能翻墙的话当然是没有什么问题,如果不能翻墙的话,就先注册一个yahoo邮箱,再用yahoo在kaggle上面注册就没问题了,否则邮箱验证的时候验证码窗口弹不出来会导致无法验证。
注册成功登陆之后,拿着你的鼠标使劲往下拉吧,上面的项目都是大牛级别参加的有偿的竞赛,我们要做的练习在下面的‘101’标签部分的‘Didit Recognizer’,这一部分都是供入门练习使用的,其中也有不少个人和team贡献出的源代可供研究。ok,我们要找的就是下面这个。
点击打开之后呢,主要有三个部分,Competition Details、Get the Data、Make a submission,Competition Details这一部分尤为重要,要仔细读这一部分的内容,这里主要对项目做了详细的描述,以及项目的具体需求。
接下来需要得到我们所需的数据,即在Get the Data下面可以找到,可得到的数据有两个,一个是train(训练集),一个事test(测试集),且均为csv文件(逗号分隔符文件),csv也是一种通用的数据文件格式,类似于jason和xml。同样,下面的描述需要仔细阅读,是关于提供的数据的基本信息和提交结果数据的格式。我在做时就没有注意到提交结果数据的格式,导致倒腾了半天。原谅我的英文水平!
2、开始练习
下载下来的数据,可以自行打开看看数据的具体形式。train数据集大小是42001*785,其中包含顶行的描述行和第一列的label列;test数据集大小是28001*784,包含了顶行的描述行。与train数据集不同的是test数据集没有label列,没错,这就是我们接下来需要做的内容,通过KNN算法,将test数据集与train数据集比对,预测出test数据集中数据的label列。
ok,下面就开始撸代码了,在这里,我用的是windows python2.7的平台。忘了提醒一点,需要将numpy库提前装上,在这里可以下载,查找对应的版本,windows下载下来的是exe程序,直接单机下一步直至安装完成。
</pre><pre name="code" class="python">
'''
Make a train of DataMining on kaggle with Digit Distinguish.
The trian-file is train.csv,and the test-file is test.csv.All of these path is'C:\Users\john\Desktop\kaggle'
'''
from numpy import *
import operator
import csv,logging,time
import logging.config
def loadTrainData():
'''
Load the train data from train.csv,and split label and data.
'''
I = []
with open('E:\\kaggle\\train.csv','rb') as file:
lines = csv.reader(file)
for line in lines:
I.append(line) #42001*785
I.remove(I[0]) # Remove the describe row
I = array(I) # Array the train data
label = I[:,0] #42000*1,Get the label column
data = I[:,1:] #42000*784, Get the data block
return normalizing(toInt(data)),toInt(label)
def loadTestData():
'''
Load the test data from test.csv,and cut the description.
'''
I = []
with open('E:\\kaggle\\test.csv','rb') as file:
lines = csv.reader(file)
for line in lines:
I.append(line) #28001*784
I.remove(I[0]) #remove description
array_I = array(I) #28000*784
return normalizing(toInt(array_I))
def toInt(array):
'''
Exchange the elements'type of array as int type from str.
'''
array=mat(array)
rows,lines = shape(array)
newArray = zeros((rows,lines))
for i in xrange(rows):
for j in xrange(lines):
newArray[i,j] = int(array[i,j])
return newArray
def normalizing(array):
'''
Normalizing the elements of input array.All the values normalizing 0 or 1(!=0)
'''
rows,lines = shape(array)
for i in xrange(rows):
for j in xrange(lines):
if array[i,j]!=0:
array[i,j]=1
return array
1、初始化数据
loadTrainData 方法和 loadTestData 方法分别将训练集和测试集的数据加载进来,这里使用到了python的csv模块。这里对csv模块不做详述,只说说用到其中的方法。打开文件的时候,mode 参数一定要给成'rb'或者'wb',否则会出现奇葩的错误,我当时就忘了加个b,折腾好长时间。
csv的reader方法:reader(iterable [, dialect='excel'][, optional keyword args]),返回值是一个迭代器,每执行一次,返回可迭代对象的一行内容。
参数说明:iterable:操作的对象必须是能够按行返回的可迭代对象,例如file对象或list对象;
dialect:编码风格,默认是‘excel’,也即是逗号分隔,csv模块中dialect也可进行自定义;
optional keyword args:操作参数,可以给指定参数覆盖dialect中的参数定义。
返回值那里对数据做了一个类型转换,因为从文件读出的数据均为字符串格式,我们后面的计算需要的是数字型的。对data block 部分进行了归一化,以简化计算,即非0 的置为1。
2、处理数据
def classify(inX,dataSet,labels,k):
'''
Classifying by K-NN algorithm
'''
inX = mat(inX)
dataSet = mat(dataSet)
labels = mat(labels)
dataSetSize = dataSet.shape[0]
diffMat = tile(inX,(dataSetSize,1)) - dataSet # Make a diff between train data and test data
sqDiffMat = array(diffMat)**2 # Make square for diffMat
sqDistance = sqDiffMat.sum(axis=1) # Sum by row
distance = sqDistance**0.5
sortedDistIndecies = distance.argsort()
classCount={}
for i in xrange(k):
votellabel = labels[0,sortedDistIndecies[i]]
classCount[votellabel] = classCount.get(votellabel,0)+1
sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
title方法,将输入的每条待预测数据inX的格式扩充成与train data 相同的格式,以求得每行待测数据与训练集每行数据的距离。对 diffMat 先平方再开方是为了对距离取绝对值,平方和开方后的同其他距离值之间的差值是等比例放大的,所以不影响后面的距离比较。
argsort方法对距离值做排序,返回每个值得下标。k是K邻域算法的参数,一般取(1,20),即取待测记录的k个邻居进行统计,for循环统计k个邻居中出现次数最多的邻居。
3、写入文件
def saveResult(result):
'''
Write the result to the result file.
'''
with open('E:\\kaggle\\result.csv','wb') as myFile:
myWriter = csv.writer(myFile)
for i in result:
tmp=[]
tmp.append(i)
myWriter.writerow(tmp)
切记mode参数要加b。
4、排版布局
这里就相当于C中的main函数了吧,从这里调用之前写的所有方法完成预测。
def handwritingClassTest():
start_time = time.time()
logger = logging.getLogger('example01')
logging.config.fileConfig('E:\\python\\log.conf')
loadTrainDataTime_start = time.time()
traintData,traintLabel = loadTrainData()
loadTrainDataTime_end = time.time()
logger.info('Traint data load successful! And load-time is:'+str(loadTrainDataTime_end-loadTrainDataTime_start))
loadTestDataTime_start = time.time()
testData = loadTestData()
loadTestDataTime_end = time.time()
logger.info('Test data load successful! And load-time is:'+str(loadTestDataTime_end-loadTestDataTime_start))
m,n = shape(testData)
resultList = []
logger.info('Digit distinguish start!')
for i in xrange(m):
classifierResult = classify(testData[i],traintData,traintLabel,5)
resultList.append(classifierResult)
if (i+1)%1000==0:
logger.info(str(i+1)+'lines data were deal succeessful.')
saveResult(resultList)
lost_time = (time.time() - start_time)/60
logger.info('The process is succeessful! Time:'+str(lost_time))
我在这里取k的值为5,用了全部的训练数据进行训练,总共下来在单机上好像跑了4个小时左右,期间跑的时间太长,刚好自己正在学日志部分,就加了个日志,自己看着也不急了,起码知道跑到哪里了。最后面会附上log的参数配置。
提交数据的格式:需要有describe 行。
提交成功,稍等片刻便会自动给出排名。
log参数配置:
#log.conf
#####################################################
[loggers]
keys=root,example01,example02
[handlers]
keys=hand01,hand02,hand03
[formatters]
keys=form01,form02
[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
datefmt=%a, %d %b %Y %H:%M:%S
[formatter_form02]
format=%(name)-12s: %(levelname)-8s %(message)s
datefmt=%a, %d %b %Y %H:%M:%S
#####################################################
[logger_root]
level=DEBUG
handlers=hand01,hand02
[logger_example01]
#level
handlers=hand01,hand02
qualname=example01
propagate=0
[logger_example02]
#level
handlers=hand01,hand03
qualname=example02
propagate=0
#######################################################
[handler_hand01]
class=StreamHandler
level=INFO
formatter=form02
args=(sys.stderr,)
[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form01
args=('E:\\kaggle\\DigitDistinguish.log','a')
[handler_hand03]
class=handlers.RotatingFileHandler
level=INFO
formatter=form02
args=('myapp.log','a',10*1024*1024,5)
########################################################