I have a matrix containing questionnaire responses and I want to do some basic pattern checking to rule out, for example, respondents who just filled in a zig-zag pattern down their Scantron sheet. I have a 1400-by-50 (person-by-item) matrix called datonly that looks like this:
> head(datonly[,1:10])
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 2 4 4 3 4 4 4 4 4
[2,] 1 1 4 NA 5 5 4 4 4 4
[3,] 2 2 2 3 3 3 3 3 3 1
[4,] 3 1 3 2 5 2 3 4 3 4
[5,] 4 2 3 1 5 3 5 5 3 4
[6,] 4 2 4 4 5 1 5 4 4 5
And as you can see there are NAs in there. Also, the possible valid responses are 1 to 5 for all questions.
I don't know the most efficient way to do this, but this matrix isn't large so efficiency isn't a big deal -- I just want to get it done and not linger on this, but I can't figure out a working method for checking, within each row, whether I find the pattern 1 2 3 4 5 4 3 2 1. I want the output of my function to look like this:
> which(ind==1)
[1] 24 55 66 67 74 79 83 90 127 131 147
[12] 154 162 172 221 222 248 260 263 316 339 390
[23] 402 408 436 440 456 457 460 492 497 504 526
[34] 544 550 568 583 597 602 623 628 632 639 682
[45] 684 689 705 727 747 750 751 763 764 769 784
where ind is a numeric vector containing 0 for each row (person) who does not display this pattern, and 1 for each row (person) who does. In this example, I would mark respondents #24, 55, 66, etc., as possibly bad respondents. Order does matter -- otherwise it wouldn't look like a zig-zag on the Scantron sheet -- but the pattern doesn't necessarily have to begin at 1 (however, I am ok with the function only checking for the one pattern given above). Any help is much appreciated!
Here's a complete answer based on my comment which will catch all sequences that are 'off by one':
#random answers
set.seed(1234)
x <- matrix(sample(c(1:5, NA), 100, TRUE, prob=c(.19,.19,.19,.19,.19, .05)), ncol = 10)
#Here's the person you want to flag
x <- rbind(x, c(1:5,4:1,2))
which(
apply(
apply(x, 1, function(z) abs(diff(z))),2,
function(zz) ifelse(sd(zz, na.rm = TRUE)==0,1,0)
)== 1)
#---
[1] 11
As I understand it, you probably want,
as.numeric(grepl("123454321",apply(datonly,1,paste0,collapse="")))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With