Content Disclaimer Copyright @2020. All Rights Reserved. 
Links : Home Index (Subjects) Contact StatsToDo 
Explanations
Javascript Program
R Codes
D
E
F
Bland and Altman (1986) discussed in details how agreements between two methods of measuring the same thing can be evaluated in nuanced details. The details and terminology of the methods are described in 3 references in the reference section, and will not be repeated here.
The rest of this panel will take users through the calculations presented in the Javascript program panel
Data Entry The data is a matrix of 2 columns. Each row represents a case being measured. The two columns, separated by white space, are the paired measurements. If a gold standard is being compared, the gold standard is in the first (left) column. The default example data on this page are generated from the computer and not real. There are only 30 pairs, too few for proper evaluation, but easier to demonstrate in this example. The data are shown in the table to the right. It represents 30 paired measurements of blood pressure. The first column (v1) is the gold standard, intraarterial catheter, and the right (v2) the measurement being compared, external electronic cuffed manometer. Initial Evaluation The first step is to estimate the paired mean = (v1+v2)/2) and paired difference (v2v1) of each pair. The original data and the estimates are presented as in the table to the right. The rest of the evaluations used the pair mean and pair difference Statistical Evaluations
The first row is the mean and Standard Deviation of the paired difference (bias and distribution of bias), and the t test for significant departure from 0. The paired difference is named bias in the context of this evaluation. If significant bias exists (p_{bias}<0.05) then the two measurements produced different results which has to be corrected when used. The second row is the results of linear regression analysis where paired difference = a + b(paired mean). The regression coefficient b representws changes to paired differences related to changing paired means, and is names proportional bias . If significant proportional bias exists (p_{b}<0.05), then the paired differences change significantly with the values of measurement, so the bias cannot be considered as stable. The remainder of the table estimate the confidence intervals of bias. Please Note that these results differed from the common references of Bland & Altman, and Hanneman (see references) as follows
95% CI Precision Estimates by Bland & Altman Approximations
The results of analysis using the algorithm described in the paper by Bland & Altman are shown in the table to the right. These are presented as the Bland and Altman plot is now commonly used to evaluate agreements between measurements Step 1, the 95% confidence, for all samples sizes, is calculated uses t=2, so that 95% CI = bias ±2SD. From the example used in the Javascript program panel
Step 2 is to calculate t, based on p=0.05 for 95% confidence interval, and the sample size of the data. In the example from the Javascript program panel, the sample size is 30, so t=2.0452. This t value is then used to calculate the precision of the mean and the 95% confidence interval borders Step 3 is to calculate the precision of the mean bias
Step 4 is to calculate the precision of the confidence interval borders
After numerical analysis, the Javascript program panel produces the Bland Altman plot, to assist the user to interpret the agreement parameters. The plot follows that described in the reference, specifically
Bland and Altman (see references) suggested the duplicate or multiple measurements be taken from each case, and the variations between measurements compared with that within measurements. As these analysis represent an additional level of complexity and precision, they are not presented. References
MacroPlot Code
To Harvest the Bitmap
This panel presents R codes for Bland and Altman's Plot, as described in https://wwwusers.york.ac.uk/~mb55/meas/ba.pdf
The R Code is translated from the Javascript code on this same page, and was initially developed to double check the arithematics The first part are utility subroutines for formating numbers and calculate probability of t # Decimal point output DStr < function (n) { if(is.numeric(n)) { if(n==round(n)) return (n) # integer no change n = sprintf("%.4f",n) # real 4 decimal points return (sub("0+$", "", n)) # remove trailing zeroes } return (n) # no a number no change } # probability of t TtoP<function(t,degF,tail) #function to calculate probability from t and df { p = 1  pt(t,df=degF) #probability 1 tail if(tail==1) return (p) return (p * 2) #orobability 2 tail } PtoT<function(p,degF,tail) #function to calculate t from probability and df { #t = qt(1p, df=degF) #t 1 tail if(tail==1) return (qt(1p, df=degF)) #t 1 tail return (qt(1 p / 2, df=degF)) #t 2 tail }The main program is as follows # Main program dat = (" v1 v2 127 134 118 120 135 142 123 115 112 117 119 123 125 125 109 111 106 122 110 115 111 109 125 127 119 118 140 139 115 111 110 110 122 122 119 115 134 137 105 105 117 112 111 113 114 115 126 119 113 115 129 127 130 129 130 130 115 120 131 126 ") dfm < read.table(textConnection(dat),header=TRUE) # conversion to data frame dfm$av < (dfm$v1 + dfm$v2) / 2 #dfm$dif < dfm$v1  dfm$v2 # Bland and Altman dfm$dif < dfm$v2  dfm$v1 # makes different of v2 over v1 (reference) dfm n = nrow(dfm) df = n  1 meanx = mean(dfm$av) sdx = sd(dfm$av) meany = mean(dfm$dif) sdy = sd(dfm$dif) sey = sdy / sqrt(n) t = meany / sey; p = TtoP(t, df, 2) * 2 # 2 tail reg < lm(formula = dfm$dif ~ dfm$av) a = summary(reg)$coefficients[1,1] b = summary(reg)$coefficients[2,1] print(paste("n=",n,"df=",df)) print(paste("Average (x=(v1+v2)/n) mean=",DStr(meanx)," SD=", DStr(sdx))) print(paste("Difference (bias, y = v2v1) mean=",DStr(meany), " SD=",DStr(sdy), " t=",DStr(t), " p=",DStr(p))) ssqx = sdx^2 * (n1) ssqy = sdy^2 * (n1) spr = b * ssqx rv = (ssqyspr^2/ssqx)/(n  2) # Residual mean Squares seB = sqrt(rv/ssqx) # SE of slope b tReg = b / seB pReg = TtoP(tReg, n2, 2) # 2 tail print(paste("Regression y=a + bx constant a=", DStr(a))) print(paste("Regression coefficient b=", DStr(b), " t=",DStr(tReg), " p=",DStr(pReg))) t90 = PtoT(0.1,df,2); t95 = PtoT(0.05,df,2); t99 = PtoT(0.01,df,2); p90 = meany + t90 * sdy n90 = meany  t90 * sdy p95 = meany + t95 * sdy n95 = meany  t95 * sdy p99 = meany + t99 * sdy; n99 = meany  t99 * sdy # counts n00 = 0; np90 = 0; nn90 = 0; np95 = 0; nn95 = 0; np99 = 0; nn99 = 0; for(i in 1:n) { v = dfm$dif[i] if(v==0) { n00 = n00 + 1 } else if(v>0) { if(v<=p90) { np90 = np90 + 1 } if(v<=p95) { np95 = np95 + 1 } if(v<=p99) { np99 = np99 + 1 } } else if(v<0) { if(v>=n90) { nn90 = nn90 + 1 } if(v>=n95) { nn95 = nn95 + 1 } if(v>=n99) { nn99 = nn99 + 1 } } } print(paste("Number of cases with no difference=",n00)) nt90 = n00 + nn90 + np90 print(paste("90% CI difference = Bias +/", DStr(t90), "SD =", DStr(n90), " to ", DStr(p90), " n>=0 = ", np90," n<=0 =", nn90, "n Within 90%CI=", nt90, "(", sprintf("%.1f",nt90/n*100),"%)")) nt95 = n00 + nn95 + np95 print(paste("95% CI difference = Bias +/", DStr(t95), "SD =", DStr(n95), " to ", DStr(p95), " n>=0 = ", np95," n<=0 =", nn95, "n Within 95%CI=", nt95, "(", sprintf("%.1f",nt95/n*100),"%)")) nt99 = n00 + nn99 + np99 print(paste("99% CI difference = Bias +/", DStr(t99), "SD =", DStr(n99), " to ", DStr(p99), " n>=0 = ", np99," n<=0 =", nn99, "n Within 95%CI=", nt95, "(", sprintf("%.1f",nt99/n*100),"%)")) t = PtoT(0.05,df,2); sey = sdy / sqrt(n) ll = meany  t * sey; ul = meany + t * sey; print(paste("Precision Estimates: mean=",DStr(meany), " SE=", DStr(sey), " 95% Confidence interval=", DStr(ll), " to ",DStr(ul))) se = sqrt(3 * sdy^2 / n) upper = meany + 2 * sdy ll = upper  t * se; ul = upper + t * se; print(paste("Upper Limit (Bias+2SD)=",DStr(upper), " SE=", DStr(se), " 95% Confidence interval=", DStr(ll), " to ",DStr(ul))) lower = meany  2 * sdy ll = lower  t * se; ul = lower + t * se; print(paste("Lower Limit (Bias2SD)=",DStr(lower), " SE=", DStr(se), " 95% Confidence interval=", DStr(ll), " to ",DStr(ul))) # Bland Altman Plot plot( # Command 1: Draw dots x = dfm$av, # x variable = average y = dfm$dif, # y variable = difference pch = 16, # size of dot xlab = "Mean=(v1+v2)/2", # x label ylab = "Diff=(v2v1)" # y lable ) # draw horizontal lines for mean +/ 2SD for difference = v1  v2 abline(h=meany) # horizontal line at mean difference abline(h=upper) # horizontal line at mean difference + 2SE abline(h=lower) # horizontal line at mean difference  2SEThe results are as follows > dfm v1 v2 av dif 1 127 134 130.5 7 2 118 120 119.0 2 3 135 142 138.5 7 4 123 115 119.0 8 5 112 117 114.5 5 6 119 123 121.0 4 7 125 125 125.0 0 8 109 111 110.0 2 9 106 122 114.0 16 10 110 115 112.5 5 11 111 109 110.0 2 12 125 127 126.0 2 13 119 118 118.5 1 14 140 139 139.5 1 15 115 111 113.0 4 16 110 110 110.0 0 17 122 122 122.0 0 18 119 115 117.0 4 19 134 137 135.5 3 20 105 105 105.0 0 21 117 112 114.5 5 22 111 113 112.0 2 23 114 115 114.5 1 24 126 119 122.5 7 25 113 115 114.0 2 26 129 127 128.0 2 27 130 129 129.5 1 28 130 130 130.0 0 29 115 120 117.5 5 30 131 126 128.5 5 [1] "n= 30 df= 29" [1] "Average (x=(v1+v2)/n) mean= 120.3833 SD= 8.9901" [1] "Difference (bias, y = v2v1) mean= 0.7667 SD= 4.7828 t= 0.878 p= 0.7743" [1] "Regression y=a + bx constant a= 0.2443" [1] "Regression coefficient b= 0.0084 t= 0.0835 p= 0.934" [1] "Number of cases with no difference= 5" [1] "90% CI difference = Bias +/ 1.6991 SD = 7.3598 to 8.8932 n>=0 = 13 n<=0 = 10 n Within 90%CI= 28 ( 93.3 %)" [1] "95% CI difference = Bias +/ 2.0452 SD = 9.0152 to 10.5485 n>=0 = 13 n<=0 = 11 n Within 95%CI= 29 ( 96.7 %)" [1] "99% CI difference = Bias +/ 2.7564 SD = 12.4164 to 13.9498 n>=0 = 13 n<=0 = 11 n Within 95%CI= 29 ( 96.7 %)" [1] "Precision Estimates: mean= 0.7667 SE= 0.8732 95% Confidence interval= 1.0192 to 2.5526" [1] "Upper Limit (Bias+2SD)= 10.3322 SE= 1.5124 95% Confidence interval= 7.2389 to 13.4255" [1] "Lower Limit (Bias2SD)= 8.7988 SE= 1.5124 95% Confidence interval= 11.8921 to 5.7056"The result plot is as shown
Contents of D:3
Contents of E:4
Contents of F:5
