Loop filter colname using R

Viewed 85

I am trying to write this in a better way using R:

  filter(V1 != 1) %>% 
  filter(V2 != 2) %>% 
  filter(V3 != 3) %>% 
  filter(V4 != 4) %>% 
  filter(V5 != 5) %>% 
  filter(V6 != 6) %>% 
  filter(V7 != 7) %>% 
  filter(V8 != 8) %>% 
  filter(V9 != 9)```


3 Answers

With BaseR you can loop like,

for(i in 1:ncol(df)) {
    
    df <- df[df[,paste0("V",i)]!=i,]

}

Fake Data:

df <- data.frame(matrix(round(runif(100,1,10)),10))
colnames(df) <- paste0("V",1:10)

Here is a way to do it with dplyr in one line. Suppose cols is a vector of column names and cutoffs is a named vector of corresponding cutoffs for each column in cols.

cols <- paste0('V', 1:9)
cutoffs <- setNames(1:9, cols)

Then, we can filter data frame df with dplyr by:

library(dplyr)
df %>% filter(across(all_of(cols), ~ .x != cutoffs[cur_column()]))

Test:

set.seed(123)
df <- as.data.frame(matrix(sample(1:9, 100*9, T), nrow = 100))
x <- df %>% filter(across(all_of(cols), ~ .x != cutoffs[cur_column()]))

colSums(mapply(`==`, x, cutoffs))
# V1 V2 V3 V4 V5 V6 V7 V8 V9 
#  0  0  0  0  0  0  0  0  0
  • use filter(across.... style of syntax
  • ~ starts an invisible function
  • .x represents the column value
  • cur_column() represents the column name. Using str_remove removes V from colname and as.numeric converts it to numeric.

So this may also do

#some sample data creation
set.seed(2021)
df <- data.frame(matrix(round(runif(100,1,10)),10))
colnames(df) <- paste0("V",1:10)

df
   V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1   5  1  2  1  3  6  1  2  6   3
2   8  9 10  9  9  7  6  7  5   7
3   7  6  5 10  5  2  2  2 10   9
4   4  6  3  9 10  6  5  9  7   6
5   7  8  6  6  2  4  9  2  4   3
6   7  3  9  3  8  3  2  5  3   9
7   7  6  9  9  9  5  2  5 10   7
8   3  9  9  3  1  4  7  4  8   8
9   8 10 10  9  1  9  3  7  5   8
10 10  6  8  5  8  8  1 10  5   7

syntax

df %>% filter(across(everything(), ~ .x != as.numeric(str_remove(cur_column(), "V")) ))

  V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1  8  9 10  9  9  7  6  7  5   7
2  7  8  6  6  2  4  9  2  4   3
3  7  3  9  3  8  3  2  5  3   9
4  7  6  9  9  9  5  2  5 10   7
5  8 10 10  9  1  9  3  7  5   8
6 10  6  8  5  8  8  1 10  5   7
Related