You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
323 lines
11 KiB
Plaintext
323 lines
11 KiB
Plaintext
8 months ago
|
*! Version 2.1 13December2017
|
||
|
************************************************************************************************************
|
||
|
* nopalera : NOPALERA algorithm
|
||
|
* Version 2: October 24, 2015
|
||
|
*
|
||
|
* Historic:
|
||
|
* Version 1 (2015-07-20): Jean-Benoit Hardouin /*ICC; rsbynpirt module*/
|
||
|
* Version 1.1 (2015-10-24): Jean-Benoit Hardouin /*NOPALERA module, ISOQOL 2015*/
|
||
|
*
|
||
|
* Jean-benoit Hardouin, phD, Assistant Professor
|
||
|
* INSERM UMR 1246-SPHERE
|
||
|
* MethodS in Patients-centered outcomes and HEalth ResEarches
|
||
|
* University of Nantes - Faculty of Pharmaceutical Sciences
|
||
|
* France
|
||
|
* jean-benoit.hardouin@anaqol.org
|
||
|
*
|
||
|
* News about this program: http://www.anaqol.org
|
||
|
*
|
||
|
* Copyright 2015,2017 Jean-Benoit Hardouin
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
************************************************************************************************************
|
||
|
|
||
|
program define nopalera, rclass
|
||
|
version 8.0
|
||
|
syntax varlist(numeric min=4) [, noGraph noBootstrap corr(numlist) NBBootstrap(int 10)]
|
||
|
|
||
|
set more off
|
||
|
tempfile file1 file3
|
||
|
qui save `file1', replace
|
||
|
preserve
|
||
|
local nbitems : word count `varlist'
|
||
|
qui count
|
||
|
local nind=r(N)
|
||
|
tokenize `varlist'
|
||
|
if mod(`nbitems',2)!=0 {
|
||
|
di in red "You must indicate an even number of items"
|
||
|
exit
|
||
|
}
|
||
|
else {
|
||
|
local nbitems=`nbitems'/2
|
||
|
}
|
||
|
if "`corr'"=="" {
|
||
|
forvalues i=1/`nbitems'{
|
||
|
local corr "`corr' 0"
|
||
|
}
|
||
|
}
|
||
|
local listofitems1
|
||
|
local listofitems2
|
||
|
forvalues i=1/`nbitems' {
|
||
|
local listofitems1 `listofitems1' ``i''
|
||
|
local listofitems2 `listofitems2' ``=`i'+`nbitems'''
|
||
|
}
|
||
|
|
||
|
di "NOPALERA: an algorithm to detect Response-shift at items level using non parametric IRT"
|
||
|
di "Number of individuals: `nind'"
|
||
|
di "Number of items: `nbitems'"
|
||
|
di "Number of Boostrap replications: `nbbootstrap'"
|
||
|
|
||
|
/*******************************************************************************
|
||
|
Une boucle pour calculer le score, définir le score maximum par item et global
|
||
|
*******************************************************************************/
|
||
|
tempvar varscore1 varscore2
|
||
|
qui gen `varscore1'=0
|
||
|
qui gen `varscore2'=0
|
||
|
label variable `varscore1' "Total score time 1"
|
||
|
label variable `varscore2' "Total score time 2"
|
||
|
local scoremax=0
|
||
|
local flag=0
|
||
|
|
||
|
|
||
|
local modamax=0
|
||
|
forvalues i=1/`nbitems' {
|
||
|
local corr`i': word `i' of `corr'
|
||
|
qui replace ``=`i'+`nbitems'''=``=`i'+`nbitems'''+`corr`i''
|
||
|
qui replace `varscore1'=`varscore1'+``i''
|
||
|
qui replace `varscore2'=`varscore2'+``=`i'+`nbitems'''
|
||
|
qui su ``i''
|
||
|
local modamax`i'=r(max)
|
||
|
qui su ``=`i'+`nbitems'''
|
||
|
local modamax`i'=r(max)
|
||
|
if r(min)!=0 {
|
||
|
local flag=1
|
||
|
}
|
||
|
local scoremax=`scoremax'+`modamax`i''
|
||
|
if `modamax`i''!=1 {
|
||
|
local flagbin=0
|
||
|
}
|
||
|
if `modamax`i''>`modamax' {
|
||
|
local modamax=`modamax`i''
|
||
|
}
|
||
|
}
|
||
|
qui save `file3', replace
|
||
|
|
||
|
/*******************************************************************************
|
||
|
Quelques tests de conformité
|
||
|
*******************************************************************************/
|
||
|
if `flag'==1 {
|
||
|
*di as error "The lower answer category of each item must be 0"
|
||
|
*exit
|
||
|
}
|
||
|
|
||
|
qui su `varscore1'
|
||
|
local maxscore=r(max)
|
||
|
qui su `varscore1'
|
||
|
if `r(max)'>`maxscore' {
|
||
|
local maxscore=r(max)
|
||
|
}
|
||
|
|
||
|
/* sauvegarde des données */
|
||
|
tempfile rsbynpirtfile rsbynpirtfile1 rsbynpirtfile2
|
||
|
tempvar score
|
||
|
qui save `rsbynpirtfile', replace
|
||
|
|
||
|
/*On récupère les données des ICC au temps 1 puis au temps 2*/
|
||
|
qui traces `listofitems1', nograph icc saveicc
|
||
|
qui drop _all
|
||
|
tempname mat1
|
||
|
qui matrix `mat1'=r(matscore)
|
||
|
qui svmat `mat1', names(t1item)
|
||
|
forvalues i=1/`nbitems' {
|
||
|
local j: word `i' of `listofitems1'
|
||
|
qui rename t1item`i' `j'
|
||
|
}
|
||
|
qui rename t1item`=`nbitems'+1' `score'
|
||
|
qui contract `score' `listofitems1'
|
||
|
qui sort `score'
|
||
|
qui save `rsbynpirtfile1', replace
|
||
|
|
||
|
qui use `rsbynpirtfile', clear
|
||
|
qui traces `listofitems2', nograph icc saveicc
|
||
|
qui drop _all
|
||
|
tempname mat2
|
||
|
qui matrix `mat2'=r(matscore)
|
||
|
qui svmat `mat2', names(t2item)
|
||
|
|
||
|
/*puis on fait un seul fichier avec les deux jeux de données*/
|
||
|
forvalues i=1/`nbitems' {
|
||
|
local j: word `i' of `listofitems2'
|
||
|
qui rename t2item`i' `j'
|
||
|
}
|
||
|
qui rename t2item`=`nbitems'+1' `score'
|
||
|
qui contract `score' `listofitems2'
|
||
|
qui sort `score'
|
||
|
qui merge 1:1 `score' using `rsbynpirtfile1'
|
||
|
|
||
|
/*représentation simultanée des ICC aux deux temps pour chaque item*/
|
||
|
if "`graph'"=="" {
|
||
|
forvalues i=1/`nbitems' {
|
||
|
twoway (line ``i'' `score') (line ``=`i'+`nbitems''' `score'), name(``i'',replace)
|
||
|
}
|
||
|
}
|
||
|
qui drop if `score'==0|`score'==`scoremax'
|
||
|
|
||
|
/*calcul des deux AUC pour chaque item*/
|
||
|
local tests
|
||
|
forvalues i=1/`nbitems' {
|
||
|
qui su ``i''
|
||
|
local AUC``i''=r(mean)
|
||
|
local AUC``i''=(`AUC``i'''*`scoremax')
|
||
|
qui su ``=`i'+`nbitems'''
|
||
|
local AUC`=`i'+`nbitems''=r(mean)
|
||
|
local AUC`=`i'+`nbitems''=(`AUC`=`i'+`nbitems'''*`scoremax')
|
||
|
tempname diff``i''
|
||
|
gen `diff``i'''=abs(``i''-``=`i'+`nbitems''')
|
||
|
qui su `diff``i'''
|
||
|
local d``i''=`r(sum)'/(`scoremax'*`modamax`i'')*100
|
||
|
local var``i''=`r(sd)'*100
|
||
|
return scalar AUC``i''=`AUC``i'''
|
||
|
return scalar AUC``=`i'+`nbitems'''=`AUC`=`i'+`nbitems'''
|
||
|
local tests `tests' b``i''=(r(AUC``=`i'+`nbitems''')-r(AUC``i''))
|
||
|
}
|
||
|
|
||
|
local abc=0
|
||
|
|
||
|
|
||
|
/* 10 bootstrap pour estimer les intervalles de confiance des différences entre les deux AUC*/
|
||
|
if "`bootstrap'"=="" {
|
||
|
tempfile file2
|
||
|
qui save `file2', replace
|
||
|
qui use `file1', clear
|
||
|
qui bootstrap `tests' , rep(`nbbootstrap') nol noh nodots : nopalera `varlist', nograph nobootstrap
|
||
|
tempname mbootstrap
|
||
|
matrix `mbootstrap'=r(table)
|
||
|
*matrix list `mbootstrap'
|
||
|
qui use `file3', clear
|
||
|
*set trace on
|
||
|
set tracedepth 1
|
||
|
|
||
|
/*Création de la matrice p qui va permettre de décaler les ICC*/
|
||
|
tempname p
|
||
|
matrix `p'=J(`=(`scoremax'+1)*(`nbitems'+1)',`=`nbitems'*3+1',.)
|
||
|
forvalues s=0/`scoremax' {
|
||
|
matrix `p'[`=`s'+1',1]=`s'
|
||
|
forvalues i=1/`nbitems' {
|
||
|
matrix `p'[`=`s'+1',`=3*`i'-1']=`s'
|
||
|
}
|
||
|
}
|
||
|
forvalues i=1/`nbitems' {
|
||
|
forvalues s=0/`scoremax' {
|
||
|
qui su ``i'' if `varscore1'==`s'
|
||
|
matrix `p'[`=`s'+1',`=3*`i'']=r(mean)
|
||
|
}
|
||
|
forvalues s=0/`scoremax' {
|
||
|
qui su ``=`i'+`nbitems''' if `varscore2'==`s'
|
||
|
*di "qui su ``=`i'+`nbitems''' if `varscore2'==`s'"
|
||
|
if `mbootstrap'[4,`i']>=0.05 {
|
||
|
matrix `p'[`=`s'+1',`=3*`i'+1']=r(mean)
|
||
|
local prec=1
|
||
|
local prec=0.01 /*pas d'arrondi*/
|
||
|
}
|
||
|
else {
|
||
|
if `nind'/`scoremax'>20 {
|
||
|
local prec=0.5
|
||
|
local prec=1
|
||
|
local prec=0.01 /*pas d'arrondi*/
|
||
|
}
|
||
|
else {
|
||
|
local prec=1
|
||
|
local prec=0.01 /*pas d'arrondi*/
|
||
|
}
|
||
|
matrix `p'[`=`i'*(`scoremax'+1)+`s'+1',`=3*`i'-1']=round(`s'+`mbootstrap'[1,`i']/(`modamax`i''),`prec')
|
||
|
matrix `p'[`=`i'*(`scoremax'+1)+`s'+1',`=3*`i'+1']=r(mean)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*matrix list `p'
|
||
|
*matrix list `p'
|
||
|
di
|
||
|
di "Research of uniform recalibration at item-level"
|
||
|
di
|
||
|
di "{hline 105}"
|
||
|
di _col(45) "Bootstrap" _col(78) " Normal-based"
|
||
|
di "Items" _col(18) "AUC t1" _col(28) "AUC t2" _col(38) "VarAUC" _col(45) "Std. Err." _col(63) "z" _col(70) "P>|z|" _col(78) "[95% Conf. Int.]" _col(96) "Correction"
|
||
|
di "{hline 105}"
|
||
|
forvalues i=1/`nbitems' {
|
||
|
di "``i''/``=`i'+`nbitems'''" _col(19) %5.2f `AUC``i''' _col(29) %5.2f `AUC`=`i'+`nbitems''' _col(39) %5.2f `=`AUC``i'''-`AUC`=`i'+`nbitems'''' _col(49) %5.2f `mbootstrap'[2,`i'] _col(59) %5.2f `mbootstrap'[3,`i'] _col(69) %5.4f `mbootstrap'[4,`i'] _col(79) %5.2f `mbootstrap'[5,`i'] _col(89) %5.2f `mbootstrap'[6,`i'] _col(100) %6.2f round(`mbootstrap'[1,`i']/(`modamax`i''),`prec')
|
||
|
}
|
||
|
di "{hline 105}"
|
||
|
local abc=1
|
||
|
}
|
||
|
if `abc'==1 {
|
||
|
drop _all
|
||
|
qui svmat `p'
|
||
|
qui rename `p'1 score
|
||
|
local testsb
|
||
|
forvalues i=1/`nbitems' {
|
||
|
qui rename `p'`=`i'*3-1' score``i''
|
||
|
qui rename `p'`=`i'*3' t1``i''
|
||
|
qui rename `p'`=`i'*3+1' t2``i''
|
||
|
/*interpolation linéaire et nouvelles ICC corrigées*/
|
||
|
qui ipolate t2``i'' score``i'' , generate(t2adj``i'')
|
||
|
forvalues j=0/`=floor(round(`mbootstrap'[1,`i']/(`modamax`i''),`prec'))' {
|
||
|
qui replace t2adj``i''=0 if score``i''==`j'&t2adj``i''==.
|
||
|
}
|
||
|
forvalues j=`=`scoremax'+floor(round(`mbootstrap'[1,`i']/(`modamax`i''),`prec'))'/`scoremax' {
|
||
|
qui replace t2adj``i''=1 if score``i''==`j'&t2adj``i''==.
|
||
|
}
|
||
|
qui gen diff``i''=abs(t2adj``i''-t1``i'')
|
||
|
qui su diff``i''
|
||
|
local ABC``i''=`r(mean)'*`scoremax'
|
||
|
return scalar ABC``i''=`ABC``i'''
|
||
|
if "`graph'"=="" {
|
||
|
qui sort score``i''
|
||
|
qui gen scoreunadj``i''=score``i''-round(`mbootstrap'[1,`i']/(`modamax`i''),`prec')
|
||
|
*twoway (line t1``i'' score``i'')(line t2``i'' score``i'')(line t2adj``i'' score``i'') ,name(``i''c,replace)
|
||
|
twoway (line t1``i'' score``i'')(line t2``i'' scoreunadj``i'')(line t2adj``i'' score``i'') ,name(``i''c,replace)
|
||
|
*di "twoway (line t1``i'' score``i'')(line t2``i'' score``i'')(line t2adj``i'' score``i'') ,name(``i''c,replace)"
|
||
|
*su
|
||
|
}
|
||
|
local testsb `testsb' c``i''=(r(ABC``i''))
|
||
|
|
||
|
}
|
||
|
|
||
|
/* 10 bootstrap pour estimer les intervalles de confiance des ABC*/
|
||
|
if "`bootstrap'"=="" {
|
||
|
tempfile file3
|
||
|
qui save `file3', replace
|
||
|
qui use `file1', clear
|
||
|
qui bootstrap `tests' , rep(`nbbootstrap') nol noh nodots : nopalera `varlist', nograph nobootstrap
|
||
|
tempname mbootstrapb
|
||
|
matrix `mbootstrapb'=r(table)
|
||
|
*matrix list `mbootstrapb'
|
||
|
di
|
||
|
di "Research of non-uniform recalibration at item-level"
|
||
|
di
|
||
|
di "{hline 77}"
|
||
|
di _col(29) "Bootstrap" _col(62) " Normal-based"
|
||
|
di "Items" _col(24) "ABC" _col(29) "Std. Err." _col(47) "z" _col(54) "P>|z|" _col(62) "[95% Conf. Int.]"
|
||
|
di "{hline 77}"
|
||
|
forvalues i=1/`nbitems' {
|
||
|
local z`i'=`ABC``i'''/`mbootstrapb'[2,`i']
|
||
|
local p`i'=2*(1-normal(abs(`z`i'')))
|
||
|
di "``i''/``=`i'+`nbitems'''" _col(23) %5.2f `ABC``i''' _col(33) %5.2f `mbootstrapb'[2,`i'] _col(43) %5.2f `z`i'' _col(53) %5.4f `p`i'' _col(63) %5.2f `=`ABC``i'''-1.96*`mbootstrapb'[2,`i']' _col(73) %5.2f `=`ABC``i'''+1.96*`mbootstrapb'[2,`i']'
|
||
|
}
|
||
|
di "{hline 77}"
|
||
|
local abc=1
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
if "`bootstrap'"=="" {
|
||
|
return matrix p=`p'
|
||
|
}
|
||
|
qui restore , preserve
|
||
|
end
|
||
|
|
||
|
|