Reputation: 1729
I'm attempting to subset 2d arrays, which can vary in dimension, and extract only the columns that contain a 3, anywhere, using the "any" function. It works well when a 3 is present in a multiple columns but fails when there is only 1 (or 0) columns containing a 3. Here is my mwe:
critval <- 3
arr1 <- as.array (matrix (c (NA, NA, 8, NA, 2, 3, 3,
NA, 3, 8, NA, 2, 3, 3,
3, NA, 8, NA, 9, 5, 4,
8, 7, NA, 9, 5, 4, 2,
8, 5, 2, 9, 7, 5, 3), ncol = 5))
arr2 <- as.array (matrix (c (3, NA, 8, NA, 9, 5, 4,
8, 7, NA, 9, 5, 4, 2), ncol = 2))
new1 <- arr1 [ , apply(arr1, 2, function(x){any(x == critval, na.rm = TRUE)})]
(jamin1 <- apply(new1, 2, function (x) min(which(x == critval))))
[1] 6 2 1 7
This works perfectly, gives me exactly what I want, the row index of the first instance of a 3 in each column, for those columns where a 3 does in fact exist. The first line of code removes any columns that do not contain a 3 anywhere.
new2 <- arr2 [ , apply(arr2, 2, function(x){any(x == critval, na.rm = TRUE)})]
(jamin2 <- apply(new2, 2, function (x) min(which(x == critval))))
Error in apply(new2, 2, function(x) min(which(x == critval))) :
dim(X) must have a positive length
However when I try it on a smaller array, the apply function in the first step does not work correctly and now the second stage throws an error. I'm sure it can be done more elegantly, and perhaps in one line, just attempting to see what it is doing. Can I write a generalized function that will work in all cases, even if none of the columns contain a 3? Thx. J
Upvotes: 0
Views: 118
Reputation: 389325
You can use drop = FALSE
in matrix subsetting to make sure that data doesn't drop its dimensions when there is single column.
Apart from that, we can use colSums
to select column which at least one value of critval
.
new1 <- arr1[, colSums(arr1 == critval, na.rm = TRUE) > 0, drop = FALSE]
apply(new1 == critval, 2, which.max)
#[1] 6 2 1 7
new2 <- arr2[, colSums(arr2 == critval, na.rm = TRUE) > 0, drop = FALSE]
apply(new2 == critval, 2, which.max)
#[1] 1
Upvotes: 1