OK, this seems to me really tricky and I may have misunderstood the question. Here is at least the beginning of an answer. As per my comments, here is an extended version of your original example
dat <- data.frame(
"one" = c(1, 1, 1, 3, NA, NA),
"two" = c(2, 2, NA, 4, 4, 9),
"three" = c(1, 1, NA, 5, 5, 5),
"four" = c(2, NA, 2, 6, 6,6)
)
# desired behaviour is foo(dat) = c(FALSE, TRUE, TRUE, FALSE, TRUE, FALSE)
For the record, this is what dat looks like:
> dat
one two three four
1 1 2 1 2
2 1 2 1 NA
3 1 NA NA 2
4 3 4 5 6
5 NA 4 5 6
6 NA 9 5 6
Desired behaviour is TRUE when a row both contains an NA, AND does not contain in any of its columns a value that is unique for that column (unique that is for the columns that are in the data after we remove the other rows that are going to be flagged TRUE - an important proviso I might be misinterpreting from your question).
Here is a very clunky solution. It involves going through the data one cell at a time! Very un-R like.
foo <- function(d){
# we are going to approach this backwards! You are a "good" row if you
# are either complete, or one of your cells is unique in its column, compared
# to the good rows
flag1 <- complete.cases(d)
flag2 <- rep(FALSE, nrow(d))
for(i in 1:nrow(d)){
for(j in 1:ncol(d)){
# check if the value in this row, col is NOT IN any of the complete cases
# of data in other rows or rows that we are keeping
if(!is.na(d[i, j]) && !d[i, j] %in% d[-i, j][flag1 | flag2]){
flag2[i] <- TRUE
}
}
}
# so flag3 is EITHER your row is complete, OR it has a unique value
flag3 <- (flag1 | flag2)
# now we return the not-good rows, so TRUE will be redundant rows
return(!flag3)
}
It works with the original test case:
> foo(dat)
[1] FALSE TRUE TRUE FALSE TRUE FALSE
However, I can think of problematic edge cases. What if the last row of our data was repeated? I'm not sure what the desired behaviour here is, but I am giving a FALSE to the first time you get a 9 in column two, then TRUE later (as these are duplicates of previous rows). See:
> dat2 <- rbind(dat, c(NA, 9, 5, 6))
> dat2
one two three four
1 1 2 1 2
2 1 2 1 NA
3 1 NA NA 2
4 3 4 5 6
5 NA 4 5 6
6 NA 9 5 6
7 NA 9 5 6
> foo(dat2)
[1] FALSE TRUE TRUE FALSE TRUE FALSE TRUE
So you might need to edit this depending on what your actual desired behaviour is in this and related edge cases. But hopefully this has given you a start.