거트만 오차는 원래 이분법적인 검사 문항에 적용하기 위해 만들어졌다. 완벽한 거트만 척도의 전제 조건은 문항들이 난이도에 따라 순서대로 배열되어 있을 때, 쉬운 문항에 대해서는 다 맞고 그 후의 어려운 항목들은 다 틀린다는 것이며 이런 예상에서 벗어나는 경우를 거트만 오차라고 한다. 거트만 오차를 계산하는 것은 문항들이 난이도에 따라 배열되어 있을 때 인접한 두 문항의 비교를 통해 이루어진다. 두 문항을 비교했을 때, 어려운 문항은 맞추었는데 쉬운 문항을 틀렸다면 거트만 오차가 발생한 것이며 아래의 식처럼 나타낼 수 있다.
$$ G = \sum_{h,e} X_{nh} (1 - X_{ne}). $$
한 개인의 점수를 각 문항의 정답을 맞췄을 때 1로, 오답일 때 0으로 코딩하여 비교를 진행한다. 위 식에서 Xnh는 비교 쌍 중 어려운 문항의 점수를, $X_{ne}$ 는 쉬운 문항의 점수를 의미하며 $X_{nh}= 1$, $X_{ne}=0$일때만 1이 산출된다. 만약 두 값이 모두 0이나 1로 같거나 $X_{nh}=0, X_{ne}=1$인 경우에는 0이 산출되어 거트만 오차가 발생하지 않았음을 나타낸다. 모든 문항 쌍의 비교에서 나타난 값의 총합이 한 개인이 발생한 거트만 오차의 수가 되는 것이다. 이러한 이분법적 거트만 오차를 리커트 척도와 같은 다분 문항에 적용하려는 시도는 Emons(2008)등에 의해 이루어졌다. 하지만 Curran(2016)¹은 Mokken scaling과 Nonparametric Polytomous Item Response Theory에 대한 이해가 필요한 Emons(2008)의 계산보다 더 간단한 다분 거트만 오차의 계산법을 제안했다. Curran(2016)은 다분 거트만 오차 계산의 기반이 되는 문항의 난이도를 각 문항의 평균값을 통해 결정할 것을 제안한다. 응답자들이 높은 값을 가질 확률이 큰, 즉 문항의 평균값이 높은 항목이 더 쉬운 문항으로 여겨진다. 예를 들어 5점 리커트 척도에서 1번 문항의 평균이 4이고 2번 문항의 평균이 1이라면 1번 문항이 더 쉬운 문항이 되는 것이다. 다분 거트만 오차는 만약 정상적인 응답자라면 2번 문항보다 더 쉬운 1번 문항에서 더 높은 값을 선택했을 것이라고 여기며 이 가정과 반대로 더 어려운 2번 문항에 대해 1번 문항보다 더 높은 값을 선택한 경우 불성실 응답으로 간주한다. 따라서 이분법적 거트만 오차처럼 쉬운 문항부터 나열하기 위해 문항의 평균이 높은 순서대로 문항을 정렬한 후 인접한 문항 쌍들 중에 더 쉬운 문항에서의 값이 어려운 문항에서의 값보다 작다면 다분 거트만 오차가 발생한 것이다. 이를 수식으로 나타내면 아래와 같다.
$$ G = \sum_{h,e} \text{ if } (X_{nh} > X_{ne}) \rightarrow 1, \text{ else} \rightarrow 0.
$$
Curran(2016)은 다분 거트만 오차가 문항 간의 비교를 통해 이루어지는 특성을 가지므로, 발생할 수 있는 최대치가 정해져 있으며 설문 문항의 수와 사용된 척도에 의해 달라진다고 하였다. 설문 문항의 수를 $k$, 선택지(5점 척도의 경우 5)의 수를 $x$라고 할 때, 만약 설문 문항의 수가 선택지의 수와 같거나 그보다 작다면 다분 거트만 오차의 최대값은 $(k-1)$이 된다. 반대로 설문 문항의 수가 선택지의 수보다 크다면 다분 거트만 오차의 최대값은 { ${(k-1)-k/x}$}의 정수값이 된다. 이는 특정 문항의 응답이 선택지의 최대값일 때 다음 응답과의 비교에서는 다분 거트만 오차가 발생할 수 없음을 전제한 결과이다. Curran(2016)은 이 기법을 이용해 불성실 응답을 탐지할 기준을 다분 거트만 오차 최대치의 50%로 제안하였다.
Curran(2016)이 제안한 다분 거트만 오차를 계산하기 위해서는 먼저 각 문항들을 난이도에 따라 쉬운 문항부터 어려운 문항까지 정렬하는 작업이 필요하다. 정렬한 이후에는 가장 쉬운 문항부터 마지막 문항까지 인접한 문항들 간의 비교를 통해서 다분 거트만 오차를 확인하면 된다. 아래 코드 예시는 2526명의 응답자를 행으로, 26개의 문항을 열로 가지는 데이터를 통해 작성되었다.
df<- sample_dataset
means<-colMeans(df, na.rm = TRUE)
df<-rbind(df, means) #df에 means를 새로운 행으로 추가.
df<- data.frame(t(df)) #t() 함수를 통해 매트릭스의 행과 열을 서로 바꿈.
df<- df%>% arrange(desc(X2527)) #문항의 평균이 가장 높은 문항부터 정렬.
df<- data.frame(t(df)) #t() 함수를 통해 원래 매트릭스 형태로 되돌림.
df$gpoly <- apply(df, 1, function(row){
gpoly <- logical(length(row) -1)
#각 문항의 값들을 두 개씩 순차적으로 비교.
for(i in 1 : (length(row) -1)){
gpoly[i] <- row[i] < row[i+1]}
#즉, 행의 'i'번째 값과 'i+1'번째 값을 비교하여 'i'번째 값이 더 작을 경우 'TRUE', 그렇지 않을 경우 'FALSE'를 ‘gpoly’ 벡터의 i번째 값에 입력.
sum(gpoly)
})
위 과정을 모두 거치고 나면 처음 설정한 ‘df’의 각 응답자들의 다분 거트만 오차 횟수가 ‘gpoly’의 새로운 행으로 추가된 것을 볼 수 있을 것이다
실제 데이터로 분석 시의 과정과 결과를 예시를 통해 설명하고자 한다. 2번 데이터의 26문항에 대한 응답을 역코딩하여 사용하였다. 실제로 적용해본 코드와 그에 따른 결과는 다음과 같다.
cds_means<-colMeans(cds_reverse, na.rm = TRUE)
df<-rbind(cds_reverse, cds_means)
df<- data.frame(t(df))
df<- df%>%arrange(desc(X2527))
df<- data.frame(t(df))
df$gpoly <- apply(df, 1, function(row){
gpoly <- logical(length(row) -1)
for(i in 1 : (length(row) -1)){
gpoly[i] <- row[i] < row[i+1]}
sum(gpoly)
})
id | gpoly |
---|---|
2211 | 14 |
111 | 12 |
332 | 12 |
368 | 12 |
1033 | 12 |
1222 | 12 |
1276 | 12 |
1361 | 12 |
1444 | 12 |
… | |
2489 | 10 |
2497 | 10 |
8 | 9 |
13 | 9 |
… | |
2363 | 0 |
2431 | 0 |
분석에 사용된 전체 데이터(cds_reverse)와 평균(cds_means)의 정의를 시작으로 코드를 진행했다. 2526명의 전체 응답자 행의 마지막에 평균 행이 더해졌기에 평균 행은 2527번째 행이며 이를 t()
함수로 뒤집었을 때 2527번째 열에 따라 문항 행을 정렬했다. 불성실 응답을 탐지하기 위한 기준은 전체 문항 수와 응답 선택지 수를 통해 위에 설명된 공식으로 계산되었다. 다분 거트만 오차의 최대 발생값은 19이며 이의 절반인 9.5가 Curran(2016)이 제시한 불성실 응답 탐지 기준으로 10번 이상의 다분 거트만 오차를 발생한 사람을 불성실 응답으로 간주했다. 그 결과 전체 응답자의 약 8.51%에 해당하는 215명이 불성실 응답으로 탐지되었다.