2014-10-20 12 views
16

Qualcuno potrebbe spiegarmi perché ottengo risultati diversi nelle mie ultime 2 righe di codice? Sembra che ho 2 oggetti identici, ma quando li uso in una funzione di applicazione, ottengo qualche problema ...Problemi tra "Sottoinsieme" e "["

df <- data.frame(a = 1:5, b = 6:2, c = rep(7,5)) 
df_ab <- df[,c(1,2)] 
df_AB <- subset(df, select = c(1,2)) 
identical(df_ab,df_AB) 
[1] TRUE 

apply(df_ab,2,function(x) identical(1:5,x)) 
    a  b 
TRUE FALSE 

apply(df_AB,2,function(x) identical(1:5,x)) 
    a  b 
FALSE FALSE 

Grazie per il vostro aiuto! :)

+2

Domanda interessante e utile! –

risposta

10

apply obbliga i dati a una matrice prima di chiamare la funzione su ogni colonna. as.matrix(df_AB) ottiene rownames non nulli, mentre as.matrix(df_ab) non lo fa:

> str(as.matrix(df_ab)) 
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2 
- attr(*, "dimnames")=List of 2 
    ..$ : NULL 
    ..$ : chr [1:2] "a" "b" 
> str(as.matrix(df_AB)) 
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2 
- attr(*, "dimnames")=List of 2 
    ..$ : chr [1:5] "1" "2" "3" "4" ... 
    ..$ : chr [1:2] "a" "b" 

Quindi, quando si apply subsest una colonna di df_AB, si ottiene un vettore di nome, che non è identico a un vettore senza nome.

apply(df_AB, 2, str) 
Named int [1:5] 1 2 3 4 5 
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ... 
Named int [1:5] 6 5 4 3 2 
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ... 
NULL 

subset sceglie righe utilizzando un vettore logico per il valore di i, ed assomiglia sottoinsiemi un data.frame con un valore non mancante per i cause questa differenza di attributo row.names:

> str(as.matrix(df[1:5, 1:2])) 
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2 
- attr(*, "dimnames")=List of 2 
    ..$ : chr [1:5] "1" "2" "3" "4" ... 
    ..$ : chr [1:2] "a" "b" 
> str(as.matrix(df[, 1:2])) 
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2 
- attr(*, "dimnames")=List of 2 
    ..$ : NULL 
    ..$ : chr [1:2] "a" "b" 

È possibile visualizzare la differenza nei data.frames stessi utilizzando la funzione .Internal(inspect(x)). Si noti che quando manca i, i valori dell'attributo row.names sono entrambi negativi, ma il secondo valore è positivo se si imposta un sottoinsieme con uno i mancante.

> .Internal(inspect(df[, 1:2])) 
@26e8500 19 VECSXP g0c2 [OBJ,NAM(2),ATT] (len=2, tl=0) 
    @1740aa0 13 INTSXP g0c3 [MARK,NAM(2)] (len=5, tl=0) 1,2,3,4,5 
    @1745f28 13 INTSXP g0c3 [MARK,NAM(2)] (len=5, tl=0) 6,5,4,3,2 
ATTRIB: 
    @27f31e8 02 LISTSXP g0c0 [] 
    TAG: @13958f8 01 SYMSXP g0c0 [MARK,LCK,gp=0x4000] "names" (has value) 
    @26e8570 16 STRSXP g0c2 [NAM(2)] (len=2, tl=0) 
     @154ed28 09 CHARSXP g0c1 [MARK,gp=0x61] [ASCII] [cached] "a" 
     @171d128 09 CHARSXP g0c1 [MARK,gp=0x61] [ASCII] [cached] "b" 
    TAG: @1395dc8 01 SYMSXP g0c0 [MARK,LCK,gp=0x4000] "class" (has value) 
    @2648f88 16 STRSXP g0c1 [MARK,NAM(2)] (len=1, tl=0) 
     @1430aa8 09 CHARSXP g0c2 [MARK,gp=0x61,ATT] [ASCII] [cached] "data.frame" 
    TAG: @139f6e0 01 SYMSXP g0c0 [MARK,LCK,gp=0x4000] "row.names" (has value) 
    @2a588f8 13 INTSXP g0c1 [] (len=2, tl=0) -2147483648,-5 
> .Internal(inspect(df[1:5, 1:2])) 
@26e8260 19 VECSXP g0c2 [OBJ,NAM(2),ATT] (len=2, tl=0) 
    @2a56e70 13 INTSXP g0c3 [NAM(1)] (len=5, tl=0) 1,2,3,4,5 
    @2a56d98 13 INTSXP g0c3 [NAM(1)] (len=5, tl=0) 6,5,4,3,2 
ATTRIB: 
    @27f9ae8 02 LISTSXP g0c0 [] 
    TAG: @13958f8 01 SYMSXP g0c0 [MARK,LCK,gp=0x4000] "names" (has value) 
    @26e8458 16 STRSXP g0c2 [NAM(2)] (len=2, tl=0) 
     @154ed28 09 CHARSXP g0c1 [MARK,gp=0x61] [ASCII] [cached] "a" 
     @171d128 09 CHARSXP g0c1 [MARK,gp=0x61] [ASCII] [cached] "b" 
    TAG: @139f6e0 01 SYMSXP g0c0 [MARK,LCK,gp=0x4000] "row.names" (has value) 
    @22a7818 13 INTSXP g0c1 [] (len=2, tl=0) -2147483648,5 
    TAG: @1395dc8 01 SYMSXP g0c0 [MARK,LCK,gp=0x4000] "class" (has value) 
    @2648f88 16 STRSXP g0c1 [MARK,NAM(2)] (len=1, tl=0) 
     @1430aa8 09 CHARSXP g0c2 [MARK,gp=0x61,ATT] [ASCII] [cached] "data.frame" 

Come Roland pointed out in his comment, questo è più facile vedere utilizzando la funzione .row_names_info.

> .row_names_info(df_ab, type=1) 
[1] -5 
> .row_names_info(df_AB, type=1) 
[1] 5 

Ciò che questi valori medi è spiegata in ?.row_names_info:

type: integer. Currently ‘type = 0’ returns the internal 
     ‘"row.names"’ attribute (possibly ‘NULL’), ‘type = 2’ the 
     number of rows implied by the attribute, and ‘type = 1’ the 
     latter with a negative sign for ‘automatic’ row names. 
+1

La ragione è che '[' crea "rownames" automatici "(vedi' .row_names_info (df_ab, type = 1) 'e' subset' crea rownames espliciti (vedi '.row_names_info (df_AB, type = 1)'). 'As .matrix' semplicemente lo propaga (una matrice non ha bisogno di nomi) – Roland

+0

+1. Sembra che 'identico (df_ab, df_AB)' debba restituire falso? –

+0

Non vedo perché la tua modifica contraddice la mia spiegazione? Se si guarda il codice di 'as.matrix.data.frame', si verifica' (.row_names_info (x) <= 0L) 'per decidere se avere o meno nomi nella matrice. – Roland

4

In una versione (usando [) le colonne sono numeri interi, mentre nell'altra versione (utilizzando subset) le colonne sono chiamati interi.

apply(df_ab, 2, str) 

int [1:5] 1 2 3 4 5 
int [1:5] 6 5 4 3 2 
NULL 


apply(df_AB, 2, str) 

Named int [1:5] 1 2 3 4 5 
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ... 
Named int [1:5] 6 5 4 3 2 
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ... 
NULL 
+0

Non è esattamente corretto. 'as.matrix' crea questa differenza se usi' apply'. Vedi 'lapply (df_AB, str)'. – Roland

6

Se si desidera confrontare i valori 1:5 con i valori nelle colonne, non si dovrebbe usare apply dal apply trasforma il frame di dati di matrici prima dell'applicazione delle funzioni. A causa dei nomi delle righe nel sottoinsieme creato con [ (vedere la risposta di @Joshua Ulrich), i valori 1:5 non sono identici a un vettore con nome che include gli stessi valori.

Utilizzare invece sapply per applicare la funzione identical alle colonne. Questo evita di trasformare i frame di dati di matrici:

> sapply(df_ab, identical, 1:5) 
    a  b 
TRUE FALSE 
> sapply(df_AB, identical, 1:5) 
    a  b 
TRUE FALSE 

Come si può vedere, in entrambi i dati incornicia i valori nella prima colonna sono identici a 1:5.

3

Guardando la struttura di questi due oggetti s prima essi ottenere sottoposti a apply mostra solo una differenza: nelle rownames, ma non una differenza che mi sarei aspettato per produrre la differenza si sta vedendo. Non vedo l'attuale offerta di Joshua di "sottoinsieme" come indicizzazione logica come spiegazione di ciò. Perché row.names = c(NA, -5L)) produce un risultato denominato quando l'estrazione con "[" non è ancora stata spiegata.

> dput(df_AB) 
structure(list(a = 1:5, b = c(6L, 5L, 4L, 3L, 2L)), .Names = c("a", 
"b"), row.names = c(NA, 5L), class = "data.frame") 
> dput(df_ab) 
structure(list(a = 1:5, b = c(6L, 5L, 4L, 3L, 2L)), .Names = c("a", 
"b"), class = "data.frame", row.names = c(NA, -5L)) 

Sono d'accordo che è la coercizione as.matrix che necessita di ulteriori indagini:

> attributes(df_AB[,1]) 
NULL 
> attributes(df_ab[,1]) 
NULL 
> attributes(as.matrix(df_AB)[,1]) 
$names 
[1] "1" "2" "3" "4" "5" 
+0

Il problema sorge in 'as.matrix.data.frame()', nella riga che chiama '.row_names_info' (da' namespace: base'). A sua volta chiama '.Internal (shortRowNames())', che fornisce un risultato diverso per i due oggetti data.frame dell'OP. Prova '.Internal (shortRowNames (df_ab, 1L))' e '.Internal (shortRowNames (df_AB, 1L))' per vedere dove diverge la conversione dei due data.frames ... –

+0

Non vedo questo come un problema con 'as.matrix.data.frame'. Non dovrebbe essere necessario determinare se '[.data.frame' ha causato che i rownames siano espliciti invece che impliciti. –

+0

Fornisce il 5 e il -5, ma non spiega perché un data.frame senza nome viene nominato. Entrambi quegli oggetti avevano quello che mi sarei aspettato di essere considerato come un rownames "automatico". –