Смуты между "Подмножеством" и "[

Может кто-нибудь объяснить мне, почему я получаю разные результаты в моих последних строках кода? Кажется, что у меня есть два одинаковых объекта, но когда я их использую в приложении, я получаю некоторые проблемы...

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

Спасибо за вашу помощь!:)

Ответы

Ответ 1

apply заставляет ваши data.frames к матрице перед вызовом функции в каждом столбце. as.matrix(df_AB) получает ненулевые имена ростов, а as.matrix(df_AB) - не:

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

Итак, когда вы apply подсетете столбец df_AB, вы получите именованный вектор, который не идентичен безымянному вектору.

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 выбирает строки с использованием логического вектора для значения i, и похоже, что подмножество data.frame с отсутствующим значением для i вызывает эту разницу в атрибуте 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"

Вы можете увидеть разницу в самих файлах данных с помощью функции .Internal(inspect(x)). Обратите внимание, что когда i отсутствует, значения атрибута row.names оба отрицательные, но второе значение является положительным, если вы подмножаетесь с отсутствующим 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"

Как Роланд указал в своем комментарии, это проще увидеть с помощью функции .row_names_info.

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

Что означают эти значения, объясняется в ?.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.

Ответ 2

Если вы хотите сравнить значения 1:5 со значениями в столбцах, вы не должны использовать apply, поскольку apply преобразует кадры данных в матрицы до того, как будут применены функции. Из-за названий строк в подмножестве, созданном с помощью [ (см. Ответ @Joshua Ulrich), значения 1:5 не идентичны именованному вектору, содержащему те же значения.

Вместо этого вы должны использовать sapply для применения функции identical к столбцам. Это позволяет избежать преобразования кадров данных в матрицы:

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

Как вы можете видеть, в обоих кадрах данных значения в первом столбце идентичны 1:5.

Ответ 3

В одной версии (используя [) ваши столбцы являются целыми числами, а в другой версии (используя subset) ваши столбцы называются целыми числами.

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

Ответ 4

Глядя на структуру этих двух объектов, прежде чем они будут представлены в apply, будет показано только одно различие: в именах ростов, но не разница, которую я ожидал бы получить разницу, которую вы видите. Я не вижу, чтобы Джошуа предлагал "подмножество" как логическое индексирование, объясняющее это. Почему row.names = c(NA, -5L)) создает именованный результат при извлечении с помощью "[" пока еще необъяснен.

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

Я согласен с тем, что это принуждение as.matrix нуждается в дальнейшем исследовании:

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