R S4 перегрузка оператора индекса для базового матричного класса

Я определил класс S4 с именем FilterCommandIndices следующим образом:

setClass('FilterCommandIndices',
     representation(rows='logical', cols='logical')
     )

Он просто содержит два слота, логические векторы, указывающие, включена ли данная строка или столбец в набор. Затем я хочу перегрузить оператор индекса, чтобы он работал с предыдущим классом. Моя первоначальная реализация выглядит так:

setMethod('[', c(x='ANY', i='FilterCommandIndices', j='missing'),
      function(x, i, j, ..., drop=TRUE) {
        if (nrow(x) != length(getRows(i)) || ncol(x) != length(getCols(i))) {
          stop('Incorrect number of dimensions')
        } else {
          return(x[getRows(i), getCols(i)])
        }
      })

В предыдущем коде getRows() и getCols() являются соответствующими тривиальными методами доступа для класса FilterCommandIndices:

setGeneric('getRows', function(object) standardGeneric('getRows'))

setMethod('getRows', 'FilterCommandIndices',
      function(object) {
        return(object@rows)
      })

setGeneric('getCols', function(object) standardGeneric('getCols'))

setMethod('getCols', 'FilterCommandIndices',
      function(object) {
        return(object@cols)
      })

Я подумал, что с помощью сигнатуры ANY я смогу заставить эту простую комбинацию класса и оператора работать даже в базовых классах, таких как простая матрица. Хотя, похоже, он работает на примере класса...

d> bar1
An object of class "FilterCommandIndices"
Slot "rows":
[1] FALSE  TRUE  TRUE  TRUE  TRUE

Slot "cols":
[1] TRUE TRUE TRUE TRUE TRUE

d> mockMethylSet
MethylSet (storageMode: lockedEnvironment)
assayData: 5 features, 5 samples 
  element names: Meth, Unmeth 
phenoData: none
Annotation
Preprocessing
  Method: unknown
  minfi version: unknown
  Manifest version: unknown

d> mockMethylSet[bar1]
MethylSet (storageMode: lockedEnvironment)
assayData: 4 features, 5 samples 
  element names: Meth, Unmeth 
phenoData: none
Annotation
Preprocessing
   Method: unknown
  minfi version: unknown
  Manifest version: unknown

... но не в базовом классе matrix:

d> zeroDetectionP
   S1 S2 S3 S4 S5
F1  0  0  0  0  0
F2  0  0  0  0  0
F3  0  0  0  0  0
F4  0  0  0  0  0
F5  0  0  0  0  0

d> zeroDetectionP[bar1]
Error en zeroDetectionP[bar1] : invalid subscript type 'S4'

В документах setMethod говорится, что вы можете определять методы, используя базовые классы в подписи, что навело меня на мысль, что я могу реализовать что-то вроде предыдущего метода, используя подпись ЛЮБУЮ и сбой только в том случае, если объект с индексом не реализует nrow(), ncol() или оператор '['.

Любая помощь или подсказка будут высоко оценены.

ОБНОВЛЕНИЕ: установите конкретный метод подписи (как предложил @hadley)

Если я установлю метод с определенной сигнатурой для базового класса матрицы...

d> getMethod('[', c(x='matrix', i='FilterCommandIndices', j='missing'))
Method Definition:

function (x, i, j, ..., drop = TRUE) 
{
    return(x) # Dummy method
}

... а затем снова попробуйте индексировать матрицу...

d> zeroDetectionP[bar1]
Error en zeroDetectionP[bar1] : invalid subscript type 'S4'

... ошибка осталась.

ОБНОВЛЕНИЕ: минимальный воспроизводимый пример

Я попытался написать минимальный сценарий, в котором я мог бы воспроизвести предыдущий сценарий. Это, я думаю, простой сценарий, который дает ту же ошибку. Как предположил @hadley, это может быть связано с тем, что нижний индекс является примитивным.

library(methods)

setClass('Indices', representation(rows='logical', cols='logical'))

setMethod('[', c(x='ANY', i='Indices', j='missing'),
      function(x, i, j, ..., drop=FALSE) {
        return(x[i@rows, i@cols])
      })

setClass('M', representation(m='matrix'))

setMethod('[', c(x='M', i='logical', j='logical'),
      function(x, i, j, ..., drop=FALSE) {
        return(x@m[i, j])
      })

anIndicesObject <- new('Indices', rows=c(TRUE, TRUE, FALSE), cols=c(FALSE, TRUE, FALSE))
aMatrix <- matrix(1:9, nrow=3)
aMobject <- new('M', m=aMatrix)

aMobject # Prints the M object
aMobject[c(TRUE, TRUE, FALSE), c(TRUE, TRUE, TRUE)] # Susbcript by logical vector
aMobject[anIndicesObject] # Subscript by Indices class
aMatrix[anIndicesObject] # Subscript a matrix by Indices --> ERROR

person Fernandez    schedule 13.03.2014    source источник
comment
Попробуйте явно указать setMethod('[', c(x='matrix', i='FilterCommandIndices', j='missing') ?   -  person hadley    schedule 13.03.2014
comment
Я уже. Отредактировал вопрос, чтобы добавить эту дополнительную информацию.   -  person Fernandez    schedule 13.03.2014
comment
Хммм, может быть потому, что [ примитивен. Но у вас больше шансов получить помощь, если вы создадите минимальный воспроизводимый пример, который можно легко скопировать и вставить в R.   -  person hadley    schedule 13.03.2014
comment
Извините, я думал, что сценарий был достаточно простым. Я отредактировал вопрос, чтобы предоставить то, что я считаю минимальным примером. Спасибо за предложение.   -  person Fernandez    schedule 14.03.2014


Ответы (1)


Еще более минимальный воспроизводимый пример:

library(methods)

setClass("Indices", representation(rows = "logical", cols = "logical"))
x <- new("Indices", rows=c(TRUE, TRUE, FALSE), cols=c(FALSE, TRUE, FALSE))
m <- matrix(1:9, nrow=3)
m[x]

# Method doesn't appear to be found for signature x = "ANY"
show_s4 <- function(x, i, j, ..., drop=FALSE) "S4"
setMethod("[", signature(x = "ANY", i = "Indices", j = "missing"), show_s4)
m[x]

# Or even with explicit "matrix" in signature
setMethod("[", signature(x = "matrix", i = "Indices"), show_s4)
m[x]
# Error in m[x] : invalid subscript type "S4"

# Describing all arguments also fails
getGeneric("[")
setMethod(
  "[", 
  signature(x = "matrix", i = "Indices", j = "missing", drop = "missing"),
  show_s4
)
m[x]

Я думаю, что ключевым является это предложение в ?Methods:

Сам по себе метод S4 не будет виден, если универсальная функция S3 вызывается напрямую. Однако примитивные функции и операторы являются исключениями: внутренний код C будет искать методы S4 тогда и только тогда, когда объект является объектом S4.

Поскольку матрица не является классом S4, вы не можете использовать ее во внутренних универсальных методах (например, [).

person hadley    schedule 14.03.2014
comment
Здорово! Большое спасибо! теперь это имеет смысл, по крайней мере, весь смысл, который я могу извлечь из этого предложения в «Методах». Спасибо за уделенное время. - person Fernandez; 14.03.2014