Reputation: 87
I'm trying to write a conditional statement that will check if any value in a vector meets a condition and then writes a result based on that. In the following example, I know c2 has a sum that is much smaller than the other columns, but in my actual data, I don't know which column has the smaller sum. I want to check if any value in the csums vector is less than .1, and if it is, write the column index to a data frame. Furthermore, in some instances there will be two columns below .1, so I need to write both column indexes to the data frame.
c1 <- runif(16,.3,.6)
c2 <- c(.01,.01,.01,.01,rep(.00,12))
c3 <- runif(16,.3,.6)
c4 <- runif(16,.3,.6)
c5 <- runif(16,.3,.6)
test.mat1 <- cbind(c1,c2,c3,c4,c5)
csums1 <- colSums(test.mat1)
csums1
c1 c2 c3 c4 c5
7.279773 0.040000 6.986803 7.200409 6.867637
c6 <- runif(16,.3,.6)
c7 <- runif(16,.3,.6)
c8 <- c(.01,.01,.01,.01,rep(.00,12))
c9 <- c(.01,.01,.01,.01,rep(.00,12))
c10 <- runif(16,.3,.6)
test.mat2 <- cbind(c6,c7,c8,c9,c10)
csums2 <- colSums(test.mat2)
csums2
c6 c7 c8 c9 c10
7.198180 7.449324 0.040000 0.040000 8.172110
A sample of the result would look like the following:
result <- matrix(c(2,0,3,4),nrow=2,byrow=T)
result
[,1] [,2]
[1,] 2 0
[2,] 3 4
where row 1 records that column 2's sum is less than .1, and row two records that columns 3 and 4 in the next data frame in the list had sums less than .1. My actual data is a list with a few thousand data frames in it, and the result data frame continues on for total length of my list. I plan on embedding this conditional statement inside a loop to go through each list element.
Upvotes: 2
Views: 231
Reputation: 452
Here is a solution that takes as input the list of matrices test.mat1
and test.mat2
that you provided:
my_list <- list(test.mat1, test.mat2)
# For each data frame in the list, compute the column sums
# and return the indices of the columns for which the sum < 0.1
res <- lapply(my_list, function(x) {
which(colSums(x) < 0.1)
})
# Get the number of columns for each element of the list
len <- lengths(res)
if(any(len == 0)) { # in case you have no values < 0.1, put a 0
res[which(len == 0)] <- 0
}
# Get your result:
result <- do.call("rbind", res)
# replace duplicated values by 0:
result[t(apply(result, 1, duplicated))] <- 0
Upvotes: 2
Reputation: 6073
Example data:
set.seed(1234)
df1 <- data.frame(
c1 = runif(16,.3,.6),
c2 = c(.01,.01,.01,.01,rep(.00,12)),
c3 = runif(16,.3,.6),
c4 = runif(16,.3,.6),
c5 = runif(16,.3,.6)
)
df2 <- data.frame(
c6 = runif(16,.3,.6),
c7 = runif(16,.3,.6),
c8 = c(.01,.01,.01,.01,rep(.00,12)),
c9 = c(.01,.01,.01,.01,rep(.00,12)),
c10 = runif(16,.3,.6)
)
Create a vector of the dataframe names to use
vec_of_df_names <- c("df1", "df2")
Loop over dataframes:
res_mat <- matrix(0, nrow=2, ncol=5)
for(i in seq_along(vec_of_df_names)) {
res <- which(colSums(get(vec_of_df_names[i])) < 0.1)
if(length(res)>0) res_mat[i, seq_along(res)] <- res
}
res_mat
Upvotes: 1