bic ton
bic ton

Reputation: 1408

How to deal with NA in two lists?

I have two lists and I want make them consistent in terms of NA. Put NA Whenever there is NA in one of the two lists without changing in anything else in the structure of the list.

set.seed(123)
m1 <- matrix(nrow=2,ncol=2,data=runif(4))
m1[1,1] <- NA
m2 <- matrix(nrow=2,ncol=2,data=runif(4))
m2[1,2] <- NA
lis <- list(m1, m2)
m1 <- matrix(nrow=2,ncol=2,data=runif(4))
m2 <- matrix(nrow=2,ncol=2,data=runif(4))
m2[2,1] <- NA
bis <- list(m1, m2)

I tried this but with no success bis[is.na(lis)]=NA

Desired output:

  > lis
[[1]]
          [,1]      [,2]
[1,]        NA 0.9568333
[2,] 0.4566147 0.4533342

[[2]]
         [,1]     [,2]
[1,] 0.9404673       NA
[2,] 0.0455565       NA

   > bis
 [[1]]
        [,1]      [,2]
[1,]        NA 0.9568333
[2,] 0.4566147 0.4533342

 [[2]]
         [,1]        [,2]
 [1,] 0.6775706        NA
 [2,] 0.5726334        NA

Upvotes: 5

Views: 86

Answers (2)

talat
talat

Reputation: 70266

Here's an option:

z <- Map("|", lapply(lis, is.na), lapply(bis, is.na))
bis <- Map(function(mat, idx) {mat[idx] <- NA; mat}, bis, z)
lis <- Map(function(mat, idx) {mat[idx] <- NA; mat}, lis, z)

However, there may be faster / more efficient approaches due to the numerous Map and lapply calls.


For the case of >2 lists you can use the following approach (assuming that each list has the same length):

# create a named list - naming is important if you want to
# assign them back to the global environment later on
mylist <- list(lis = lis, bis = bis, kis = kis)

n <- max(lengths(mylist))
z <- lapply(1:n, function(i) {
  Reduce(`+`, Map(function(y) is.na(y[[i]]), mylist))>0
})

mylist <- lapply(mylist, function(mat) {
  Map(function(m, idx) {m[idx] <- NA; m}, mat, z)
})

# to assign them back to the global environment, run:
list2env(mylist, envir = .GlobalEnv)

Now your original lists are modified in the global environment.

Sample data:

set.seed(123)
n <- 4
lis <- list(
  m1 = matrix(nrow=n,ncol=n,data=sample(c(NA, 1:10), n*n, TRUE)), 
  m2 = matrix(nrow=n,ncol=n,data=sample(c(NA, 1:10), n*n, TRUE))
)
bis <- list(
  m1 = matrix(nrow=n,ncol=n,data=sample(c(NA, 1:10), n*n, TRUE)), 
  m2 = matrix(nrow=n,ncol=n,data=sample(c(NA, 1:10), n*n, TRUE))
)
kis <- list(
  m1 = matrix(nrow=n,ncol=n,data=sample(c(NA, 1:10), n*n, TRUE)), 
  m2 = matrix(nrow=n,ncol=n,data=sample(c(NA, 1:10), n*n, TRUE))
)

Upvotes: 3

CJB
CJB

Reputation: 1809

Using Map to create a list of matrices with the NA positions as NA:

naposmtx <- Map(function(mtx1, mtx2){
    nasmtx <- mtx1 + mtx2 # because NA + non-NA = NA
    nasmtx[!is.na(nasmtx)] <- 0
    nasmtx
}, lis, bis)

Then:

lis <- Map(`+`, lis, naposmtx)
bis <- Map(`+`, bis, naposmtx)

Upvotes: 4

Related Questions