2013-01-24 10 views
10

Ich laufe immer weiter und frage mich, ob es eine einfache Work-Around ist. Für einige Situationen finde ich es logischer inSubsetting ein data.frame mit einer Ganzzahl-Matrix

eine Matrix über subsetting
N <- 12 
N.NA <- 6 
dat <- data.frame(V1=runif(N),V2=runif(N)) 
sel.mat <- matrix(c(sample(seq(N),N.NA),sample(ncol(dat),N.NA,replace=TRUE)),ncol=2) 

Dies funktioniert für die Auswahl zu denken, aber nicht für den Ersatz:

> dat[sel.mat] 
[1] 0.2582569 0.8455966 0.8828083 0.5384263 0.9574810 0.5623158 
> dat[sel.mat] <- NA 
Error in `[<-.data.frame`(`*tmp*`, sel.mat, value = NA) : 
    only logical matrix subscripts are allowed in replacement 

Mir ist klar, dass ein Grund für die Fehlermeldung gibt es (es würde nicht wissen, was zu tun wäre, wenn mehrere Ersetzungen auf dasselbe Element zeigen würden), aber das hindert R nicht daran, einen ganzzahligen Ersatz für Vektoren zuzulassen (z. B. dat$V1[c(2,3)] <- NA).

Gibt es eine bequeme Möglichkeit, Ersatz durch Integer-Matrix zu ermöglichen?

+1

In der aktuellen R-devel Snapshot, 'dat [sel.mat] <- NA' ** ** wird unterstützt. Die Matrix-Indizierung mit Ersetzung ist somit ab R-3.0.0 verfügbar. (Siehe meine Antwort unten für weitere Details.) –

Antwort

2

FWIW, Matrix Indizierung mit Ersatz im aktuellen R-devel Snapshot funktioniert (und wird Sei ein Teil von R-3.0.0). Offensichtlich hatte jemand in R-core den gleichen Wunsch wie du.

Wie im R-devel NEWS file dokumentiert:

Matrix Indizieren von Datenrahmen von zweispaltigen numerischer Indizes wird nun für den Ersatz sowie Extraktion

unterstützt.

Eine Demonstration:

dat[sel.mat] 
## [1] 0.3355509 0.4114056 0.2334332 0.6597042 0.7707762 0.7783584 
dat[sel.mat] <- NA 
dat[sel.mat] 
## [1] NA NA NA NA NA NA 

R.version.string 
# [1] "R Under development (unstable) (2012-12-29 r61478)" 
+0

Die Zeit löst wirklich alle Probleme. –

+0

Ja. Sie haben den Code bereits im Oktober 2012 hinzugefügt und werden es erst im April 2013 in eine nummerierte Version schaffen, aber ich denke, so sieht ein guter Betatest immer aus! –

0

Vielleicht mit einer Schleife?

for (i in 1:nrow(sel.mat)) 
{ 
    dat[sel.mat[i,1],sel.mat[i,2]] <- NA 
} 

> dat 
       V1   V2 
    1   NA 0.27002155 
    2 0.7253383   NA 
    3   NA 0.63847293 
    4 0.1768720 0.64586587 
    5 0.3796935 0.62261843 
    6 0.6751365 0.78328647 
    7 0.9801140 0.82259732 
    8   NA 0.08606641 
    9 0.3294625 0.44110121 
    10 0.2830957   NA 
    11 0.6868594 0.09767882 
    12 0.9802349   NA 
7

es zu einer Matrix konvertieren:

dat.m <- as.matrix(dat) 
dat.m[sel.mat] <- NA 
> dat.m 
      V1   V2 
[1,] 0.2539189   NA 
[2,] 0.5216975   NA 
[3,] 0.1206138 0.14714848 
[4,] 0.2841779 0.52352209 
[5,] 0.3965337   NA 
[6,] 0.1871074 0.23747235 
[7,] 0.2991774   NA 
[8,]  NA 0.09509202 
[9,] 0.4636460 0.59384430 
[10,] 0.5493738 0.92334630 
[11,] 0.7160894   NA 
[12,] 0.9568567 0.80398264 

bearbeiten erklären, warum wir einen Fehler mit data.frame

dat.m[sel.mat] <- NA 

haben entspricht folgendes zu tun:

temp <- dat 
dat <- "[<-"(temp, sel.mat, value=NA) 

Error in `[<-.data.frame`(temp, sel.mat, value = NA) : 
only logical matrix subscripts are allowed in replacement 

jetzt kann ich die follwing tun und es funktioniert:

dat <- "[<-"(as.matrix(temp), sel.mat, value=NA) 
6

Sie könnten eine logische Matrix erstellen, die auf der ganzen Zahl Matrix basiert:

log.mat <- matrix(FALSE, nrow(dat), ncol(dat)) 
log.mat[sel.mat] <- TRUE 

Diese Matrix könnte mit zum Ersetzen Werte in den Datenrahmen verwendet werden NA (oder andere Werte):

is.na(dat) <- log.mat 

Das Ergebnis:

  V1   V2 
1 0.76063534   NA 
2 0.27713051 0.10593451 
3 0.74301263 0.77689458 
4 0.42202155   NA 
5 0.54563816 0.10233017 
6   NA 0.05818723 
7 0.83531963 0.93805113 
8 0.99316128 0.61505393 
9 0.08743757   NA 
10 0.95510231 0.51267338 
11 0.14035257   NA 
12 0.59408022   NA 

Damit können Sie das ursprüngliche Objekt als Datenrahmen beibehalten, wodurch Spalten unterschiedlicher Typen möglich sind.

2

In R die Ausdrücke

dat[sel.mat] 
dat[sel.mat] <- NA 

sind Methoden und S3 entspricht

`[.data.frame`(x=dat, i=sel.mat) 
`[<-.data.frame`(x=dat, i=sel.mat, value=NA) 

seit class(dat) ist "data.frame".

Sie können den Quellcode

`[.data.farme` 
`[<-.data.frame` 

schauen und ändern Sie es zu dem, was Sie wollen.


In Ihrem Fall vielleicht möchten Sie:

`[<-.data.frame` <- function(x, i, j, value) { 
    if (class(i) != "matrix") return(base:::`[<-.data.frame`(x, i, j, value)) 
    if (class(i[1]) != "integer") return(base:::`[<-.data.frame`(x, i, j, value)) 
    # check the length of i and value here 
    if (length(value) < nrow(i)) { 
    if (nrow(i) %% length(value) != 0) warning("some warning message should be here") 
    value <- rep(value, nrow(i) %/% length(value) + 1) 
    } 
    value <- value[1:nrow(i)] 
    for(index in 1:nrow(i)) { 
    x[i[index,1], i[index,2]] <- value[index] 
    } 
    return(x) 
} 

versuchen es:

N <- 12 
N.NA <- 6 
dat <- data.frame(V1=runif(N),V2=runif(N)) 
sel.mat <- matrix(c(sample(seq(N),N.NA),sample(ncol(dat),N.NA,replace=TRUE)),ncol=2) 
dat[sel.mat] <- NA 
dat 
+0

(+1) auch. Nicht sicher, warum das nicht mehr Upvotes anders als das Neuschreiben von Basisfunktionen bekam, wird normalerweise am besten vermieden, um Verwirrung zu vermeiden. Aber es ist eine schöne Erklärung. –

Verwandte Themen