9

I want to convert all 0s in the matrices of a list into NAs. I figured out a way how to achieve this task. However, it is too complex and I think there should be an easy way how to do it. Here some example data:

ABlue <- list("111.2012"=matrix(c(1, 0, 6, 0, 1, 0),
                            nrow = 1, byrow = T),
          "112.2012"=matrix(c(6, 2, 2, 0, 3, 1),
                            nrow = 1, byrow = T),
          "111.2011"=matrix(c(3, 2, 0, 0, 1, 9),
                            nrow = 1, byrow = T),
          "112.2011"=matrix(c(1, 2, 0, 0, 7, 0),
                            nrow = 1, byrow = T))
CNTRYs <- c("USA", "GER", "UK", "IT", "CND", "FRA")
ABlue <- lapply(ABlue  , "colnames<-",  CNTRYs ) # gets names from Country list

Important is that the original matrices already have Country names as colnames, so it would be nice to match with this list (ABlue).

Here the way I use until now:

ABlue.df<-data.frame(do.call("rbind",ABlue)) # two step approach to replace 0 with NA according to: "http://stackoverflow.com/questions/22870198/is-there-a-more-efficient-way-to-replace-null-with-na-in-a-list"
ABlue.df.withNA <- sapply(ABlue.df, function(x) ifelse(x == 0, NA, x))
ABlueNA <- split(ABlue.df.withNA, 1:NROW(ABlue.df.withNA)) # is again a list (of vectors)  
names(ABlueNA) <- names(ABlue) # list with old names
ABlueNAdf <- lapply(ABlueNA, function(x) as.data.frame(x)) # turned into list of dfs of one column
ABlueNAdfT <- lapply(ABlueNAdf, function(x) t(x)) # transponed to list of dfs of one row and 206 cols
ABlueNAdfTnam <- lapply(ABlueNAdfT  , "colnames<-",  CNTRYs ) # gets names from Country list
ABlueNAdfTnam <- lapply(ABlueNAdfTnam  , "rownames<-",  1:NROW(ABlueNAdfTnam[1]) )
ABlue2 <- ABlueNAdfTnam

Ideas how to reduce lines and complexity? Thanks

Edit: I want to have the same structure as in the original data!

N.Varela
  • 910
  • 1
  • 11
  • 25

2 Answers2

17

You can use replace, like this:

lapply(ABlue, function(x) replace(x, x == 0, NA))
# $`111.2012`
#      USA GER UK IT CND FRA
# [1,]   1  NA  6 NA   1  NA
# 
# $`112.2012`
#      USA GER UK IT CND FRA
# [1,]   6   2  2 NA   3   1
#
# $`111.2011`
#      USA GER UK IT CND FRA
# [1,]   3   2 NA NA   1   9
#
# $`112.2011`
#      USA GER UK IT CND FRA
# [1,]   1   2 NA NA   7  NA

Or, as @roland suggested:

lapply(ABlue, function(x) {x[x == 0] <- NA; x})

Or, if you have a pipe addiction:

library(purrr)
ABlue %>% map(~ replace(.x, .x == 0, NA))
A5C1D2H2I1M1N2O1R2T1
  • 190,393
  • 28
  • 405
  • 485
0

We can also use for.

for (i in 1:length(ABlue)) {
  ABlue[[i]][ABlue[[i]]==0] <- NA
}

ABlue
# $`111.2012`
#      USA GER UK IT CND FRA
# [1,]   1  NA  6 NA   1  NA
# 
# $`112.2012`
#      USA GER UK IT CND FRA
# [1,]   6   2  2 NA   3   1
#
# $`111.2011`
#      USA GER UK IT CND FRA
# [1,]   3   2 NA NA   1   9
#
# $`112.2011`
#      USA GER UK IT CND FRA
# [1,]   1   2 NA NA   7  NA

I'm wondering do we have any other functions to iterate over a list except lapply and for.

Ven Yao
  • 3,680
  • 2
  • 27
  • 42