Check the following code, it should work and solve your problem. # function is.err returns 1 if criteria for erroneous entry are met, else returns 0 for each district. is.err <- function(df) { # df = data frame with entries for 1 district with(df, { C <- C[!is.na(C)] # C is the counts with any missing data out of it. C1 <- c(NA, C) # C1 is the shifted C vector by q position dif.C.C1 <- abs(C1-c(C,NA)) # absolute value of difference between entry in C and next entry in C1 dif.C.C1 <- dif.C.C1[!is.na(dif.C.C1)] # removes all NA p.C.C1 <- dif.C.C1/C[1:length(dif.C.C1)] # calculates proportion if (any(dif.C.C1 > 5) & any(p.C.C1 > 0.5)){ # checks the criteria e <- 1 } else { e <- 0 } return(e) }) } # main function gets the value of erroneous entries by districts by entering data of each district into is.err function and returns a data frame showing status 0: if no error and 1: if error and corresponding district main <- function(df.main) { with(df.main, { #browser() d <- unique(df.main$D) r <- rep(100,length(d)) for (i in 1:length(d)) { r[i] <- is.err(df.main[df.main$D == d[i],]) } return(data.frame(D=d, r=r)) }) } # first load the above code into R console and then run the lines below, check ret. you should get result. df <- data.frame(D=c(rep("a",3),rep("b",3),rep("c",3)),Y=rep(c(2005:2007),3),C=c(10,0,9,1,0,1,5,NA,4)) ret <- main(df)