Reputation: 282
I have a dataframe where I want to reduce its size by selected all instances TRUE appears in dataframe.
Here is the dataframe:
df<-structure(c("1", "2", "3", "4", "5", "TRUE", "FALSE", "TRUE",
"TRUE", "FALSE", "FALSE", "FALSE", "FALSE", "TRUE", "FALSE",
"TRUE", "FALSE", "FALSE", "TRUE", "FALSE", "a", "b", "c", "d",
"e"), .Dim = c(5L, 5L), .Dimnames = list(NULL, c("A", "B_down",
"C_down", "D_down", "E")))
To reduce the dataframe to where TRUE is, I used this code:
df[which(apply(df[,c(2:4)],1,function(x) any(x)=="TRUE")),]
However, I manually selected columns c(2:4) - B_down, C_down, D_down, as they have _down ending. How do I choose these columns dynamically in R, without hard coding it.
I see in a [post here] (filtering with multiple conditions on many columns using dplyr), one can use select(df, ends_with("_down")), but this only gives me a partial dataframe. I want the whole dataframe structure to be maintained as above.
Thank you for your help.
Upvotes: 1
Views: 5354
Reputation: 389175
There are better ways to handle your data but continuing the workflow from your example this would work.
df[apply(df[, endsWith(colnames(df), "_down")], 1, function(x) any(x == "TRUE")), ]
# A B_down C_down D_down E
#[1,] "1" "TRUE" "FALSE" "TRUE" "a"
#[2,] "3" "TRUE" "FALSE" "FALSE" "c"
#[3,] "4" "TRUE" "TRUE" "TRUE" "d"
Another approach would be
df[rowSums(df[, endsWith(colnames(df), "_down")] == "TRUE") > 0, ]
# A B_down C_down D_down E
#[1,] "1" "TRUE" "FALSE" "TRUE" "a"
#[2,] "3" "TRUE" "FALSE" "FALSE" "c"
#[3,] "4" "TRUE" "TRUE" "TRUE" "d"
Upvotes: 2
Reputation: 887691
We can use type.convert
with is.logical
to check the column types dynamically
i1 <- sapply(as.data.frame(df, stringsAsFactors = FALSE),
function(x) is.logical(type.convert(x)))
If it is only for those columns that have 'down' in the column name, have another logical vector with grepl
i2 <- grepl("_down$", colnames(df))
i1 & i2
# A B_down C_down D_down E
# FALSE TRUE TRUE TRUE FALSE
Upvotes: 3