2016-01-21 12 views
5

Ho due elenchi e voglio renderli coerenti in termini di NA. Metti NA Ogni volta che c'è NA in uno dei due elenchi, senza modificare nulla nella struttura dell'elenco.Come trattare con NA in due elenchi?

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) 

ho provato questo, ma senza successo bis[is.na(lis)]=NA

output desiderato:

> 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 

risposta

3

Ecco un'opzione:

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) 

Tuttavia, ci possono essere più veloce/approcci più efficienti a causa dei numerosi Map e lapply chiamate.


Per il caso di> 2 liste è possibile utilizzare il metodo seguente (supponendo che ciascuna lista ha la stessa lunghezza):

# 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) 

Ora le vostre liste originali vengono modificati nel contesto globale.

dati Esempio:

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)) 
) 
+0

sostituire la prima riga con: 'z <- Mappa (funz ione (...) {punti <- as.list (...); arr <- do.call (abind, c (dots, along = 3)); apply (arr, 1: 2, any)}, lapply (lis, is.na), lapply (bis, is.na)) '. Penso che dovrebbe funzionare. Probabilmente però più lento. Ha bisogno del pacchetto 'abind'. La chiave sta sostituendo '|' con 'any'. – Bazz

+0

@Bazz, vai avanti e aggiungilo alla risposta. Vedrò se riesco a trovare un approccio diverso –

+0

è un adattamento della tua risposta, non mia. 'as.list' dovrebbe essere semplicemente' list'. – Bazz

4

Utilizzo Map per creare una lista di matrici con NA posizioni NA:

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

Poi:

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

Buona opzione, ho confrontato le nostre soluzioni e appaiono ugualmente veloci (+1) –

+0

Grazie. Prenderò in considerazione la funzione 'Map' - questo è nuovo per me. – Bazz

+0

È semplicemente 'mapply' con' simplify = FALSE' –