Можете ли вы "связать" или обеспечить альтернативную реализацию данных. Frame в R?

В Perl (и, возможно, других языках) вы можете "привязать" переменную, чтобы заменить ее встроенным поведением с пользовательским поведением. Например, хэш-таблицу можно связать с пользовательскими подпрограммами "get" и "fetch", которые, например, запрашивают BerkeleyDB, чтобы данные были постоянными и не ограничивались ОЗУ, но все еще выглядит и действует как обычный хеш для Perl.

Возможно ли что-то подобное с R? В частности, я думал, поскольку data.frame похож на таблицу в реляционном db, что если a data.frame привязаны к чему-то вроде SQLite, это позволит R обрабатывать очень большие кадры данных (я набивал 100GB + в SQLite) без каких-либо изменений кода.

Ответ 1

Как отмечают комментарии, на эту идею (или подобное) уже построена горстка пакета.

data.table и dplyr исключительно хороши в работе с очень большими кадрами данных и их запросом. Если data.frame на самом деле > 100 ГБ, я бы скорее рекомендовал data.table, который, кажется, превосходит dplyr в пределе nrow- > Inf. Оба они имеют отличную поддержку в stackoverflow, если вам это нужно.

Однако, чтобы на самом деле ответить на ваш вопрос (и быть полезным будущим читателям этого вопроса): да, можно обеспечить дополнительную функцию с помощью R, чтобы обеспечить альтернативное поведение. На самом деле это очень просто с системой отправки S3. Я рекомендую этот ресурс, чтобы узнать больше.

Я дам вам сжатую версию: Если у вас есть объект класса "myclass", вы можете написать функцию f.myclass, чтобы сделать то, что вы хотите.

Затем вы определяете общую функцию f:

f <- function(obj, ...) UseMethod("f", obj, ...)

Когда вы вызываете f(obj), функция, вызываемая UseMethod, зависит от класса obj.

Если obj имеет класс "myclass", то f.myclass будет вызываться на obj.

Если функция, которую вы хотите переопределить, уже существует, скажем plot, вы можете просто определить plot.myclass, который будет использоваться, когда вы вызываете plot в объект "myclass". Общая функция уже существует, нет необходимости переопределять ее.

Чтобы изменить класс объекта (или добавить новый класс к существующим классам, что чаще встречается, чтобы не нарушать поведение, которое вы не хотите изменять), вы можете использовать class<-.

Вот глупый пример.

> print.myclass <- function(x) {
    print("Hello!")}

> df <- data.frame(a=1:3)
> class(df)
[1] "data.frame"
> df #equivalent to print(df)
  a
1 1
2 2
3 3

> class(df) <- append(class(df), "myclass")
> class(df)
[1] "data.frame" "myclass"   

> class(df) <- "myclass"
> class(df)
[1] "myclass"
> df
[1] "Hello!"
> str(df) # checking the structure of df: the data is still there of course
List of 1
 $ a: int [1:3] 1 2 3
 - attr(*, "row.names")= int [1:3] 1 2 3
 - attr(*, "class")= chr "myclass"

Есть несколько тонкостей, например, какая функция вызывается, если есть несколько классов, в каком порядке и т.д. Я отсылаю вас к подробному объяснению системы S3.

Как бы вы переопределили поведение функций. Перезапишите их как f.myclass, а затем создайте объекты класса "myclass".

В качестве альтернативы вы можете переопределить f.targetclass. Например, снова с помощью print и data.frame:

> print.data.frame <- function(x) {
         print(paste("data.frame with columns:", paste(names(x), collapse = ", ")))} # less silly example!
> df <- data.frame(a=1:3, b=4:6)
> df
[1] "data.frame with columns: a, b"