馬 由,湯 艷,解 斐
(中國(guó)電子科技集團(tuán)第十五研究所 軟件測(cè)評(píng)中心,北京 100083)
本文采用兩種模型來(lái)實(shí)現(xiàn)軟件缺陷數(shù)預(yù)測(cè),即一般的線性回歸模型和貝葉斯網(wǎng)絡(luò)模型,并基于LASSO嵌入式特征選擇算法選擇最優(yōu)的因子集合。LASSO能夠在訓(xùn)練模型時(shí)同時(shí)選擇因子,并通過(guò)L1算法避免過(guò)擬合問(wèn)題[1],最后分析線性回歸和貝葉斯網(wǎng)絡(luò)模型在軟件缺陷預(yù)測(cè)方面的優(yōu)缺點(diǎn)。
在軟件缺陷數(shù)的預(yù)測(cè)中,因子是離散數(shù)據(jù)和連續(xù)數(shù)據(jù)結(jié)合的,采用線性回歸和貝葉斯網(wǎng)絡(luò)進(jìn)行預(yù)測(cè),能夠得出這種混合數(shù)據(jù)更適應(yīng)于用哪種模型來(lái)預(yù)測(cè)。
線性回歸是采用歷史數(shù)據(jù)來(lái)預(yù)測(cè)未來(lái)結(jié)果的最直接和有效的方法,一般的現(xiàn)實(shí)問(wèn)題都可以用線性回歸模型來(lái)描述和預(yù)測(cè),且結(jié)果往往很準(zhǔn)確。
貝葉斯網(wǎng)絡(luò)是一個(gè)有向無(wú)環(huán)圖,圖中的節(jié)點(diǎn)代表一個(gè)獨(dú)立屬性,節(jié)點(diǎn)的邊代表兩個(gè)獨(dú)立屬性之間的依賴關(guān)系[2]。如圖1所示是一個(gè)貝葉斯網(wǎng)絡(luò)示例。

圖1 貝葉斯網(wǎng)絡(luò)
貝葉斯網(wǎng)絡(luò)結(jié)構(gòu)確定時(shí),其中所有屬性的聯(lián)合概率分布作為監(jiān)督值,可以處理有監(jiān)督學(xué)習(xí)的數(shù)據(jù)仿真及預(yù)測(cè);當(dāng)網(wǎng)絡(luò)結(jié)構(gòu)不能事先明確,需要評(píng)價(jià)函數(shù)來(lái)學(xué)習(xí)得到網(wǎng)絡(luò)模型,評(píng)價(jià)函數(shù)常見(jiàn)的有AIC、BIC以及極大似然估計(jì),都能夠基于假設(shè)近似的得到一個(gè)較為準(zhǔn)確的模型[3]。當(dāng)網(wǎng)絡(luò)結(jié)構(gòu)確立后,就可以通過(guò)已知屬性預(yù)測(cè)未知屬性,例如通過(guò)吉布斯采樣采集已知屬性樣本,在網(wǎng)絡(luò)中計(jì)算未知屬性的后驗(yàn)概率。
LASSO是一種常用的嵌入式特征選擇方法,用來(lái)解決特征值較多,LASSO方法有嵌入式特征選擇方法的優(yōu)點(diǎn),即能夠同時(shí)訓(xùn)練模型和因子選擇,LASSO相較其它嵌入式特征因子,選擇的另一個(gè)顯著優(yōu)勢(shì)是通過(guò)L1正則化形成了稀疏矩陣[4],能夠最小化的對(duì)相關(guān)因子進(jìn)行降維,且訓(xùn)練結(jié)果較為準(zhǔn)確,常用于復(fù)雜因子模型構(gòu)建前的數(shù)據(jù)預(yù)處理。
缺陷影響因子是在軟件生命周期過(guò)程中作為輸入能夠影響輸出結(jié)果并引起缺陷的因素。本文所述的因子是從預(yù)測(cè)對(duì)象形成之前的階段中得到的,例如預(yù)測(cè)需求規(guī)格說(shuō)明的缺陷數(shù),其缺陷影響因子可能是需求分析人員的水平、用戶的表達(dá)程度、需求規(guī)格說(shuō)明文檔的規(guī)模等,由此可以得知缺陷影響因子的值既有離散數(shù)也有連續(xù)數(shù)。
由于一個(gè)軟件缺陷在未確定原因之前,可能有多個(gè)影響因子[10],因此借鑒故障樹(shù)分析的思路,采用構(gòu)建無(wú)環(huán)有向圖的方式來(lái)分析軟件的缺陷影響因子。
因在軟件生命周期過(guò)程活動(dòng)中引入的各種因素具有直接、間接兩種關(guān)系,沒(méi)有循環(huán)關(guān)系,因此可以構(gòu)建有向無(wú)環(huán)圖。
具體采用兩種構(gòu)建方式,一種是正向構(gòu)建,即根據(jù)經(jīng)驗(yàn)通過(guò)原因推導(dǎo)缺陷,一種是逆向構(gòu)建,通過(guò)常用的故障模式來(lái)逆向推導(dǎo)原因。構(gòu)建有向無(wú)環(huán)圖默認(rèn)兩個(gè)前提,一是缺陷和故障模式是一個(gè)抽象的概念,即在圖中只能作為一個(gè)節(jié)點(diǎn);二是圖中的原因能夠量化,一般對(duì)定量的因子直接采集數(shù)據(jù),對(duì)定性的因子則采用專家法進(jìn)行量化。
正向構(gòu)建時(shí),是由原因推導(dǎo)出可能的結(jié)果,構(gòu)建步驟如下:
從軟件生命周期活動(dòng)中選取一個(gè)活動(dòng)或一個(gè)產(chǎn)品作為起點(diǎn)v0;
分析起點(diǎn)與缺陷相關(guān)的能夠量化的因素,每個(gè)因素作為有向無(wú)環(huán)圖的起點(diǎn)w0i(i=1,2,3…n,n為因素個(gè)數(shù));
以v0為輸入,分析其輸出活動(dòng)或產(chǎn)品,記為v1i(i=1,2,3…m,m為輸出個(gè)數(shù));
分析v1i,得到所有可能與缺陷相關(guān)且能夠量化的因素,記為w1j(j=1,2,3…l,l為因素個(gè)數(shù));
分析w0i與w1j,如果存在相關(guān)關(guān)系則繪出由w0i到w0j的路徑;
循環(huán)上述步驟構(gòu)建有向無(wú)環(huán)圖V和W,直到目標(biāo)節(jié)點(diǎn),即缺陷節(jié)點(diǎn)。
上述步驟中,缺陷節(jié)點(diǎn)的輸入可以是直接影響因子,也可以是間接影響因子,隨應(yīng)用經(jīng)驗(yàn)和分析粒度決定。上述步驟構(gòu)建的W圖中所有的節(jié)點(diǎn)wij即缺陷影響因子,具體W圖如圖2所示。

圖2 缺陷影響因子關(guān)系有向無(wú)環(huán)W圖
逆向構(gòu)建網(wǎng)絡(luò)步驟與正向構(gòu)建思想相同,思路相反,這里不再贅述。為后續(xù)計(jì)算方便,圖2用表格的形式表示見(jiàn)表1。

表1 W圖的表格化形式
注:節(jié)點(diǎn)表示因子,前驅(qū)表示輸入,后繼表示輸出,邊表示與后繼的相關(guān)度。
將上節(jié)所構(gòu)建的有向無(wú)環(huán)圖進(jìn)行模型化處理即形成貝葉斯網(wǎng)絡(luò)模型,進(jìn)而求解最優(yōu)貝葉斯網(wǎng)絡(luò)作為預(yù)測(cè)模型。
求最優(yōu)貝葉斯網(wǎng)絡(luò)是一個(gè)NP難題,常用的算法有貪心算法和約束消減算法,因缺陷預(yù)測(cè)前不確定影響因子的重要性,采用貪心算法結(jié)合LASSO特征選擇可以避免重要因子被剔除,貪心算法需要一個(gè)初始的網(wǎng)絡(luò)模型[11]。
假設(shè)有N個(gè)缺陷影響因子,構(gòu)建網(wǎng)絡(luò)為B,因子參數(shù)為θ,將網(wǎng)絡(luò)B的結(jié)構(gòu)記為
B=
(1)
其中,G為一個(gè)有向無(wú)環(huán)圖,如圖2所示,每一個(gè)節(jié)點(diǎn)對(duì)應(yīng)一個(gè)影響因子,參數(shù)θ用來(lái)描述因子之間的關(guān)系,假設(shè)屬性xi在圖G中的父節(jié)點(diǎn)為πi,則將每個(gè)屬性的條件概率結(jié)構(gòu)記為
θxi/yi=PB(xi/π)
(2)
假設(shè)G有n個(gè)節(jié)點(diǎn),則網(wǎng)絡(luò)G的屬性x1,x2,x3…xn的聯(lián)合概率分布定義為
(3)
在式(3)中,πi為第i個(gè)類別,訓(xùn)練集為D,則有
(4)
式中:Dπi,xi為第i個(gè)屬性在第i個(gè)分類里的個(gè)數(shù),Dπi為第i個(gè)分類的個(gè)數(shù)。依據(jù)經(jīng)驗(yàn)僅僅比例估計(jì)條件概率結(jié)果較為脆弱,尤其當(dāng)屬性較多訓(xùn)練數(shù)據(jù)較少的情況下,因此將式(4)改為如下形式
(5)
式(5)采用m估計(jì)方法,其中m是等價(jià)樣本大小的參數(shù),p為用戶指定的參數(shù),一般依據(jù)m*p=1對(duì)p進(jìn)行指定。
屬性量化值為連續(xù)型數(shù)值,則
(6)

(7)
為避免屬性和類別混淆,式(7)中πj為訓(xùn)練集D中第j個(gè)類別,m為類別個(gè)數(shù),n為屬性個(gè)數(shù),當(dāng)預(yù)測(cè)目標(biāo)是一個(gè)值時(shí),m=1。
貝葉斯網(wǎng)絡(luò)一般的學(xué)習(xí)算法是針對(duì)初始網(wǎng)絡(luò)模型定義一個(gè)評(píng)分函數(shù),求評(píng)分函數(shù)的最大或最小值進(jìn)而得到訓(xùn)練模型[12]。本文確定訓(xùn)練模型的思路是將初始貝葉斯網(wǎng)絡(luò)模型與LASSO特征選擇方法結(jié)合后進(jìn)行學(xué)習(xí),在得到一個(gè)系數(shù)稀疏解的同時(shí)將訓(xùn)練模型確定下來(lái)的過(guò)程。
(1)確定模型
按照LASSO特征選擇方法,線性回歸以及概率函數(shù)以平方損失函數(shù)為評(píng)估模型,優(yōu)化目標(biāo)隨屬性的離散和連續(xù)特征不同而不同[11]。依據(jù)經(jīng)驗(yàn),結(jié)合上節(jié)的初始網(wǎng)絡(luò)模型構(gòu)建優(yōu)化目標(biāo)評(píng)估函數(shù)如下
(8)
式(8)中,θT為矩陣θ的轉(zhuǎn)置矩陣,λ為正則化參數(shù),在LASSO中規(guī)定λ>0。
(2)求解模型參數(shù)
求解目標(biāo)函數(shù)是求解使式(8)的值最小的θ的過(guò)程,在計(jì)算過(guò)程中最小二乘法是數(shù)學(xué)求解過(guò)程,但需要x滿秩,而在缺陷預(yù)測(cè)中并不能保證訓(xùn)練集的每個(gè)因子都有量化值,所以采用梯度下降算法進(jìn)行求解。
(9)
然后帶入梯度下降算法,梯度下降算法如下:
輸入:數(shù)據(jù)集D;
特征集A;
評(píng)估函數(shù)f(θ);//式(8)和式(9),y和x作為常量
步長(zhǎng)step;//根據(jù)經(jīng)驗(yàn)取值,會(huì)影響迭代收斂速度
迭代閾值ξ
正則化參數(shù)λ;
過(guò)程:
初始化變量
f_change=f(θ);//兩次殘差的差值
f_current=f(θ);//當(dāng)前殘差

循環(huán)求解
While D 非空 do
//梯度下降θ的值
θ=θ-step*f(θ′);//依據(jù)經(jīng)驗(yàn)f(θ′) 為f(θ) 的導(dǎo)數(shù)
//計(jì)算殘差差值
f_change=f_current-f(θ);
//計(jì)算殘差
f_current=f(θ);
end while
將θ加入到中;
將該步的數(shù)據(jù)對(duì)y,x從D中刪除;
End while

(3)缺陷預(yù)測(cè)

本文采用某單位近五年積累的軟件研制過(guò)程的數(shù)據(jù)作為訓(xùn)練和測(cè)試樣本,采集項(xiàng)目類型為辦公自動(dòng)化項(xiàng)目需求規(guī)格說(shuō)明的缺陷數(shù),以及其它因子。生產(chǎn)這些數(shù)據(jù)的研發(fā)過(guò)程是嚴(yán)格按照GJB5000A-2008《軍用軟件研制能力成熟度模型》中的規(guī)定而制定和執(zhí)行的,因此這些數(shù)據(jù)具有普遍性和代表性。具體如圖3所示。

圖3 需求缺陷影響因子集合
由于圖3中的缺陷因子在某單位的數(shù)據(jù)積累中都是定量的數(shù)據(jù),可以直接采集到。
對(duì)上述各屬性進(jìn)行特征值選擇,采用R語(yǔ)言中的glmnet包進(jìn)行,主要代碼如下:
#lasso特征選擇代碼
mydata<-read.csv(file="C:\Users\user17\Downloads\樣本數(shù)據(jù).csv",header=TRUE)
x=as.matrix(mydata[, 1:8])
y=as.matrix(mydata[, 9])
la<-lars(x,y,type="lar")
plot(la)
summary(la)
運(yùn)行結(jié)果如下:
LAR sequence
Computing X′X…
LARS Step 1: Variable 2 added
LARS Step 2: Variable 3 added
LARS Step 3: Variable 4 added
LARS Step 4: Variable 5 added
LARS Step 5: Variable 6 added
LARS Step 6: Variable 1 added
LARS Step 7: Variable 7 added
LARS Step 8: Variable 8 added
LARS Step 9: Variable 9 added
Computing residuals, RSS etc…
LARS/LAR
Call: lars(x=x,y=y, type="lar", trace=10)
Df Rss Cp
0 1 178.15 30.2213
1 2 165.24 16.2195
2 3 160.34 15.7000
3 4 160.11 13.6305
4 5 158.34 9.0796
5 6 156.87 6.6245
6 7 154.23 4.8069
7 8 148.40 8.0000
7 9 132.40 10.0000
依據(jù)運(yùn)行結(jié)果,選擇CP值最小的步驟,即選擇屬性x2,x3,x4,x5,x6,x1,x7, 去掉x8,x9。
依據(jù)上一節(jié)結(jié)果嗎,去掉了x中與y相關(guān)性弱的節(jié)點(diǎn),采用R語(yǔ)言進(jìn)行線性回歸,代碼如下:
predata<-read.table("E:\mayou\test.csv",header=FALSE,sep=",")
y<-mydata[,8]
x1<-mydata[,1]
x2<-mydata[,2]
x3<-mydata[,3]
x4<-mydata[,4]
x5<-mydata[,5]
x6<-mydata[,6]
x7<-mydata[,7]
plot<-lm(y~x1+x2+x3+x4+x5+x6+x7,data=predata)
plot
#結(jié)果
Call:
lm(formula=y~x1+x2+x3+x4+x5+x6+x7,data=predata)
Coefficients:
(Intercept) x1 x2 x3 x4
42.437 42.4607 0.9408 -4.4549 -2.9723
x5 x6 x7
4.1206 -0.7707 -8.2829
#回歸診斷
plot(plot)
從運(yùn)行結(jié)果可知,最后的模型為:
Y=2.4607x1+0.9408x2-4.4549x3-2.9723x4+4.1206x5-0.7707x6-8.2829x7, 依據(jù)上述預(yù)測(cè)模型,假設(shè)置信區(qū)間為0.95,將測(cè)試集帶入,代碼和結(jié)果如下:
predata<-read.table("E:\mayou\test.csv",header=FALSE,sep=",")
plot<-lm(v8~V1+V2+V3+V4+V5+V6+V7,data=predata)
newdata<-read.table("E:\mayou\test1.csv",header=FALSE,sep=",")
predict(plot,data.frame(newdata[,1:7]))
#結(jié)果
1 2 3 4
13.6510211 -0.6531836 13.6781614 26.7401970
5 6 7 8
7.7557199 23.2157111 31.3797127 22.2473188
9 10 11
5.0710729 24.7817223 2.4761034
與真實(shí)值的對(duì)比結(jié)果如下:

323027257131092243793326323518202621
誤差均值為2.8。
根據(jù)各因子的潛在關(guān)系,構(gòu)建貝葉斯網(wǎng)絡(luò)模型,如圖4所示。

圖4 貝葉斯網(wǎng)絡(luò)模型
采集圖4中所有節(jié)點(diǎn)的數(shù)據(jù),按照3∶1的比例分為訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)集合。基于訓(xùn)練數(shù)據(jù),用R語(yǔ)言繪制貝葉斯網(wǎng)絡(luò)模型[12],計(jì)算得到因子系數(shù)θ的值,主要代碼如下:
#安裝R貝葉斯庫(kù)
install.packages("D:/bnlearn_4.1.zip", repos = NULL, type = "source")
#引入庫(kù)
library(bnlearn)
#導(dǎo)入數(shù)據(jù)
mydata1<-read.table("D:/Rworkspace/sample.csv",header=FALSE,sep=",")
#離散化缺陷數(shù)
c8<-t(v8)
cc8<-sort(c8)
group<-c(seq(1,max(cc8),10),max(cc8))
t8<-cut(c8,breaks=group,labels=1:(length(group)-1))
t8
[1] 3 2 1 1 4 1 2 2 2 4 4 2 1 1 2 6 5 1 3 2 1 1 1 1 3 3 4 6 5 4 7 11 1 2 3
[36] 2 5 5 2 1 4 1 1
netdata<-cbind(predata[,1:7],t8)
#繪制貝葉斯節(jié)點(diǎn)
bayesnet<-empty.graph(names(mydata))
bayesnet<-set.arc(bayesnet,"V1","V2")
bayesnet<-set.arc(bayesnet,"V3","V2")
bayesnet<-set.arc(bayesnet,"V1","V3")
bayesnet<-set.arc(bayesnet,"V1","V4")
bayesnet<-set.arc(bayesnet,"V3","V4")
bayesnet<-set.arc(bayesnet,"V6","V4")
bayesnet<-set.arc(bayesnet,"V1","V8")
bayesnet<-set.arc(bayesnet,"V2","V8")
bayesnet<-set.arc(bayesnet,"V3","V8")
bayesnet<-set.arc(bayesnet,"V4","V8")
bayesnet<-set.arc(bayesnet,"V5","V8")
bayesnet<-set.arc(bayesnet,"V6","V8")
bayesnet<-set.arc(bayesnet,"V7","V8")
plot(bayesnet)
fitted<-bn.fit(bayesnet,mydata,method="mle")
fitted
pre<-predict(fitted,data=mydata,node='V8')
#顯示網(wǎng)絡(luò)
plot(bayesnet)
#用導(dǎo)入的數(shù)據(jù)訓(xùn)練模型
fitted<-bn.fit(bayesnet,mydata1,method="mle")
#預(yù)測(cè)
newdata<-read.table("E:\mayou\test1.csv",header=FALSE,sep=",")
pre<-predict(fitted,data=newdata,node=′V8′)
運(yùn)行結(jié)果中,需求規(guī)格缺陷節(jié)點(diǎn)的概率結(jié)果為:
Parameters of node V8 (Gaussian distribution)
Conditional density: V8|V1+V2+V3+V4+V5+V6+V7
Coefficients:
(Intercept) V1 V2
4.47062148 0.25553858 0.09860272
V3 V4 V5
-0.44597170 -0.33725753 0.40965399
V6 V7
-0.02004204 -0.81317686
Standard deviation of the residuals: 1.466314
由于缺陷數(shù)據(jù)是連續(xù)值,進(jìn)行了離散化,因此需要將預(yù)測(cè)結(jié)果的離散值轉(zhuǎn)換為缺陷數(shù),本文以最大閾值為預(yù)測(cè)值,與真實(shí)結(jié)果對(duì)比見(jiàn)表2。

表2 貝葉斯網(wǎng)絡(luò)預(yù)測(cè)結(jié)果與真實(shí)結(jié)果對(duì)比
貝葉斯網(wǎng)絡(luò)預(yù)測(cè)結(jié)果誤差均值為:3.5。
由上述兩個(gè)實(shí)例結(jié)果可知,兩個(gè)模型都比較適合預(yù)測(cè)缺陷數(shù)量,但由于缺陷數(shù)是連續(xù)值,貝葉斯網(wǎng)絡(luò)預(yù)測(cè)模型的準(zhǔn)確度要低一些,且計(jì)算較復(fù)雜。
由于在構(gòu)建貝葉斯網(wǎng)絡(luò)時(shí)具有極大的主觀性,因此當(dāng)數(shù)據(jù)本身已經(jīng)是二次加工后的,例如定性數(shù)據(jù)轉(zhuǎn)換為定量數(shù)據(jù)這種情況,則貝葉斯網(wǎng)絡(luò)的預(yù)測(cè)準(zhǔn)確度就會(huì)明顯降低。因此,當(dāng)預(yù)測(cè)樣本數(shù)據(jù)經(jīng)過(guò)二次加工后形成,且具有主觀性的情況下,采用線性模型預(yù)測(cè)結(jié)果可能更準(zhǔn)確一些。
軟件缺陷由于多種原因?qū)е拢趯?shí)踐中由于各種原因量化的不準(zhǔn)確性等問(wèn)題,理論預(yù)測(cè)的結(jié)果往往不盡如人意,要解決類似的問(wèn)題,應(yīng)該從數(shù)據(jù)積累入手,逐步尋找規(guī)律提升預(yù)測(cè)的準(zhǔn)確性。