对于有些存在缺失的数据来说,扔掉和重新获取是不可取的,所以有以下这些方法来解决数据缺失的问题:
对于该实战中使用的数据集,在预处理阶段需要做两件事:
机器学习中如何处理缺失数据这个问题没有标准答案,取决于实际应用中的需求。
原始的数据集经过预处理之后保存为了两个文件:horseColicTest.txt和horseColicTraining.txt。这两个数据集和原始数据集见文末给出的链接。
使用Logistic回归方法进行分类,所需要做的就是把测试集上的每个特征向量乘以最优化方法得来的回归系数,再将该乘积结果求和,最后输入到Sigmoid函数中,如果对应的函数值大于0.5就预测类别标签为1。下面看看实战中的代码,首先是文件内容的读取、Sigmoid函数以及梯度下降算法函数,这边不再赘述:
'''
数据加载
'''
def loadDataSet(filePath):
f = open(filePath)
dataList = []
labelList = []
for line in f.readlines():
currLine = line.strip().split(' ')
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i]))
dataList.append(lineArr)
labelList.append(float(currLine[21]))
return dataList, labelList
'''
sigmoid函数
'''
def sigmoid(inX):
return 1.0 / (1 + np.exp(-inX))
'''
随机梯度下降算法
'''
def stocGradAscent(dataList, labelList, numIter=150):
dataArr = np.array(dataList)
m, n = np.shape(dataArr)
weights = np.ones(n)
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4 / (1.0 + j + i) + 0.01 # 步长为动态变化
rand = int(np.random.uniform(0, len(dataIndex)))
choseIndex = dataIndex[rand]
h = sigmoid(np.sum(dataArr[choseIndex] * weights))
error = h - labelList[choseIndex]
weights = weights - alpha * error * dataArr[choseIndex]
del (dataIndex[rand])
return weights
接下去是分类函数,该函数以回归系数和特征向量作为输入来计算对应的Sigmoid值,如果Sigmoid值大于0.5则函数返回1。
'''
进行分类
'''
def classifyVector(inX, weights):
prob = sigmoid(np.sum(inX * weights))
if prob > 0.5:
return 1.0
else:
return 0.0
再接下去是在测试集上计算分类错误率,这边返回的错误率多次运行得到的结果可能稍有不同,主要是因为其中有随机的成分在里面。只有当梯度下降算法得到的回归系数已经完全收敛,那么结果才是确定的。
'''
在测试集上计算分类错误率
'''
def colicTest(trainWeights, testDataList, testLabelList):
errorCount = 0 # 判断错误的数量
testCount = 0 # 测试集总共的数量
testCount = len(testDataList)
for i in range(testCount):
if int(classifyVector(np.array(testDataList[i]), trainWeights)) !=
int(testLabelList[i]):
errorCount += 1
errorRate = float(errorCount)/testCount
return errorRate
最后只要调用如下的主函数即可获得10次运行之后的平均分类错误率
def main():
numTests = 10
errorSum = 0.0
trainDataList, trainLabelList = loadDataSet("horseColicTraining.txt")
testDataList, testLabelList = loadDataSet("horseColicTest.txt")
for i in range(numTests):
trainWeights = stocGradAscent(trainDataList, trainLabelList, 500)
errorSum += colicTest(trainWeights, testDataList, testLabelList)
print("%d次的平均错误率为%f"%(numTests, errorSum/numTests))
某次运行程序之后,得到的平均分类错误率如下(即输出结果),如果调整stocGradAscent
函数中参数numIter
的值和梯度下降算法中的步长,那么平均可以降到20%左右。
10次的平均错误率为0.329851
附:数据集及代码
本文所有数据集及代码,均可在https://github.com/DawnGuoDev/MachineLearningStudy/tree/master/LogisticRegression中获取。