机器学习能够帮助测试工作者做什么呢?答案一定有很多。随着对机器学习的越来越熟悉,就一定能够能将它应用到更多测试领域。对于目前的我们团队来说,就有能够根据一些特征值来预测迭代的BUG数量的需求,甚至反过来可以帮助我们进行迭代中特征值的最优化,来达到更合理的故事分配、人员配比等。
首先我们的目标是在需求达到共识的情况下,根据迭代需求故事数量、技术挑战数量、迭代天数、人力数量等特征值预测某次迭代的BUG数量。当然,真正决定BUG数量的特征值绝不止这些,我们暂时采用MVP(最小化可行产品)的方式开始,可以让我们先看到效果而不至于陷入太多的前置思考,浪费时间。
接下来就是模型选取,由于有很多特征值,我们暂时采用多元线性回归模型来作为我们的假设模型:
最小化损失函数时,可以通过梯度下降法来一步步的迭代求解。具体的内容可以参考https://www.cnblogs.com/pinard/p/5970503.html,说实话,这篇文章帮助了我普及了很多相关的数学知识,真是全还给老师了。。。
然后就是准备数据了,我们目前已有的数据不多,不过对于实验来说无所谓:
把数据搞到txt里面去(Iterationdata.txt),展示形式是:
数据准备完,并定义好迭代次数(iterations)、学习率(alpha)、模型参数初始值(theta),就可以运行下面的代码了:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu May 17 10:17:08 2018
@author: xingshulin
"""
#-*- coding: UTF-8 -*-
import numpy as np
#加载数据
def load_exdata(filename):
data = []
with open(filename, 'r') as f:
for line in f.readlines():
line = line.split(',')
current = [float(item) for item in line]
data.append(current)
return data
# 特征缩放
def featureNormalize(X):
X_norm = X;
mu = np.zeros((1, X.shape[1]))
sigma = np.zeros((1, X.shape[1]))
for i in range(X.shape[1]):
mu[0, i] = np.mean(X[:, i]) # 均值
sigma[0, i] = np.std(X[:, i]) # 标准差
X_norm = (X - mu) / sigma
return X_norm, mu, sigma
# 计算损失
def computeCost(X, y, theta):
m = y.shape[0]
# J = (np.sum((X.dot(theta) - y)**2)) / (2*m)
C = X.dot(theta) - y
J2 = (C.T.dot(C)) / (2 * m)
return J2
# 梯度下降
def gradientDescent(X, y, theta, alpha, num_iters):
m = y.shape[0]
# 存储历史误差
J_history = np.zeros((num_iters, 1))
for iter in range(num_iters):
theta = theta - (alpha / m) * (X.T.dot(X.dot(theta) - y))
J_history[iter] = computeCost(X, y, theta)
return J_history, theta
# 预测y值
def predict(data):
testx = np.array(data)
testx = ((testx - mu) / sigma)
testx = np.hstack([testx, np.ones((testx.shape[0], 1))])
bugNum = testx.dot(theta)
print('predit value is %f ' % (bugNum))
# 加载数据
data = load_exdata('/Users/xingshulin/Downloads/Iterationdata.txt');
data = np.array(data,np.float64) #数据是浮点型
print('data value is: ')
print(data)
# 迭代次数
iterations = 100
# 学习率
alpha = 0.1
#数据特征输入,采用数据集一行的,第1,2,3,4个数据,然后将其变成一行,所以用shape
x = data[:, ( 1,2,3,4)].reshape((-1, 4))
print('x value is: ')
print(x)
y = data[:, 5].reshape((-1, 1)) #输出特征,数据集的第5位
print('y value is: ')
print(y)
m = y.shape[0]
x, mu, sigma = featureNormalize(x)
X = np.hstack([x, np.ones((x.shape[0], 1))])
# 总共有4个特征值输入,所以theta是5维(多一个θ0),θ0+θ1x1+...+θnxn;详见https://www.cnblogs.com/pinard/p/5970503.html中的梯度下降法的矩阵方式描述
theta = np.zeros((5, 1))
#theta = np.array([[10],[10],[10],[10],[10]])
print('theta init value is: ')
print(theta)
J_history, theta = gradientDescent(X, y, theta, alpha, iterations)
# 打印最后10个损失值
print('J_history:')
print(J_history[-10:-1])
print('Theta found by gradient descent: ')
print(theta)
# 开始预测
predict([10,2,7,8]) #输入为4维
最终运行的结果为:
runfile('/Users/xingshulin/多元线性回归预测.py', wdir='/Users/xingshulin')
data value is:
[[ 1. 9. 6. 10. 8. 64.]
[ 2. 7. 0. 15. 8. 89.]
[ 3. 9. 1. 12. 9. 42.]
[ 4. 7. 1. 10. 9. 33.]
[ 5. 5. 2. 5. 15. 44.]
[ 6. 6. 0. 4. 8. 16.]
[ 7. 10. 0. 3. 10. 17.]]
x value is:
[[ 9. 6. 10. 8.]
[ 7. 0. 15. 8.]
[ 9. 1. 12. 9.]
[ 7. 1. 10. 9.]
[ 5. 2. 5. 15.]
[ 6. 0. 4. 8.]
[10. 0. 3. 10.]]
y value is:
[[64.]
[89.]
[42.]
[33.]
[44.]
[16.]
[17.]]
theta init value is:
[[0.]
[0.]
[0.]
[0.]
[0.]]
J_history:
[[67.53350557]
[67.53239752]
[67.53137251]
[67.53042429]
[67.52954709]
[67.52873557]
[67.52798481]
[67.52729025]
[67.52664767]]
Theta found by gradient descent:
[[-2.87136585]
[ 5.72753034]
[20.87608252]
[ 3.92605147]
[43.57027125]]
predit value is 31.249887
可以看到,打印结果中的theta初始值都是0,如果初始值不同,最终学习的模型参数也有可能不同,原因就是梯度下降求得的只是局部最小值;当然如果损失函数是凸函数则一定是最优解。由于有局部最优解的风险,需要多次用不同初始值运行算法,关键损失函数的最小值,选择损失函数最小化的初值。
还有一点,通过打印的J_history最后10个数据我们可以看到在目前迭代数和学习率情况下损失函数值的变化,从结果看已经变化不大了,所以可以理解为目前已经接近局部最小值了。当然,我们可以去改变迭代数和学习率(如改成10000和0.01),但对于目前数据量来说,影响不大。
记录下未来会对此次学习结果造成影响的因素:
- 特征数量,如增加新的特征:开发人员级别
- 特征值数量,即样本数量,随着样本数量增多,结果应该更准确
- 模型参数初始值
- 选择其他模型,如多元非线性模型
具体的回归预测方法可见下面链接中的“多元线性回归分析预测法案例分析”部分:
http://wiki.mbalib.com/wiki/%E5%A4%9A%E5%85%83%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92%E5%88%86%E6%9E%90%E9%A2%84%E6%B5%8B%E6%B3%95
学习率:http://baijiahao.baidu.com/s?id=1591531217345055627&wfr=spider&for=pc