2014-10-20 9 views
16

Czy ktoś mógłby mi wyjaśnić, dlaczego otrzymuję inne wyniki w 2 ostatnich liniach kodu? Wydaje się, że mam 2 identyczne obiekty, ale kiedy ich używać w funkcji zastosowania, mam pewne problemy ...Kłopoty między "podzbiorami" i "["

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 

dzięki za pomoc! :)

+2

ciekawych i przydatnych pytanie! –

Odpowiedz

10

apply wymusza twoje dane.frame na macierzy przed wywołaniem funkcji w każdej kolumnie. as.matrix(df_AB) dostaje zakaz zerowe rownames, natomiast as.matrix(df_ab) nie:

> 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" 

Więc kiedy apply subsest kolumna df_AB, masz nazwie wektor, który nie jest identyczny do nienazwanej wektorze.

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 wybiera wiersze za pomocą logicznego wektor dla wartości i, i wygląda na to, podzbiorów do data.frame z niebrakującymi wartości dla i przyczyn tej różnicy w atrybucie 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" 

Możesz zobaczyć różnicę w samych danych.frames przy użyciu funkcji .Internal(inspect(x)). Zauważ, że gdy brakuje wartości i, wartości atrybutu row.names są ujemne, ale druga wartość jest dodatnia, jeśli podzestawiono na nieużyty i.

> .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" 

Jak Roland pointed out in his comment, jest to łatwiejsze do zobaczenia przy użyciu funkcji .row_names_info.

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

Co te wartości oznaczają wyjaśniono w ?.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

Powodem jest to, że '[tworzy" automatyczne "rownames (zobacz' .row_names_info (df_ab, type = 1) 'i' subset' tworzy jawne rownames (patrz '.row_names_info (df_AB, type = 1)'). 'As .matrix' po prostu to propaguje (macierz nie musi mieć rownames) – Roland

+0

+1 Wygląda na to, że 'identyczny (df_ab, df_AB)' powinien zwracać fałsz? –

+0

Nie rozumiem, dlaczego twoja edycja jest sprzeczna z moimi wyjaśnieniami? Jeśli spojrzysz na kod 'as.matrix.data.frame' to sprawdza' (.row_names_info (x) <= 0L) ', aby zdecydować czy mieć rownames w macierzy. – Roland

4

W jednej wersji (przy użyciu [) Twoje kolumny są liczbami całkowitymi, natomiast w drugiej wersji (przy użyciu subset) kolumn są nazywane liczbami całkowitymi.

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

To nie jest dokładnie poprawne. 'as.matrix' tworzy tę różnicę, jeśli użyjesz' apply'. Zobacz 'lapply (df_AB, str)'. – Roland

6

Jeśli chcesz porównać wartości 1:5 z wartościami w kolumnach, nie należy używać apply od apply przekształca ramek danych do macierzy, zanim zostaną zastosowane funkcje. Ze względu na nazwy wierszy w podzbiorze utworzonym za pomocą [ (patrz odpowiedź @Joshua Ulricha), wartości 1:5 nie są identyczne z nazwanym wektorem obejmującym te same wartości.

Powinieneś zamiast tego użyć sapply, aby zastosować funkcję identical do kolumn. To pozwala uniknąć przekształcenia ramek danych do macierzy:

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

Jak widać, w obu ramek danych wartości w pierwszej kolumnie są identyczne 1:5.

3

Patrząc na strukturę tych dwóch przedmiot s przed dostają przedłożonego apply pokazuje tylko jedna różnica: w rownames, ale nie jest to różnica, że ​​ja nie powinien powodować różnicę widzisz. Nie uważam obecnej oferty Joshua za "podzbiór" za logiczne indeksowanie za wyjaśnienie tego. Dlaczego row.names = c(NA, -5L)) tworzy nazwany wynik, gdy wyodrębnianie z "[" jest jeszcze niewyjaśnione.

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

zgadzam się, że jest to przymus as.matrix który wymaga dalszych badań:

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

Problem pojawia się w 'as.matrix.data.frame()', w linii, która wywołuje '.row_names_info' (z' namespace: base'). To z kolei wywołuje '.Internal (shortRowNames())', który daje inny wynik dla dwóch obiektów data.frame OP. Spróbuj '.Internal (shortRowNames (df_ab, 1L))' i '.Internal (shortRowNames (df_AB, 1L))', aby zobaczyć, gdzie konwersja dwóch data.frames rozbieżności ... –

+0

Nie widzę tego jako problem z 'as.matrix.data.frame'. Nie powinno się ustalać, czy "[.data.frame" powodowało, że rownames jest jawny, a nie niejawny. –

+0

To dostarcza 5 i -5, ale nie wyjaśnia, dlaczego data.frame bez rownames ma nazwę. Oba te obiekty miały to, czego oczekiwałbym, że zostaną uznane za "automatyczne" rownames. –