Должен ли я использовать фреймы данных S3 в моем пакете? - PullRequest
1 голос
/ 21 апреля 2020

У меня есть пакет, который использует класс S4 на основе data.frame:

setClass(Class="foobar",
  slots=c(a="character", b="character", c="character"),
  contains="data.frame")

Работает как задумано. Тем не менее, я наблюдаю странные предупреждения при объединении с tidyverse:

df <- data.frame(ID=1:5)
df2 <- new("foobar", df)
as_tibble(df2)

Последний оператор вызывает предупреждение:

Warning message:
In class(x) <- c(subclass, tibble_class) :
  Setting class(x) to multiple strings ("tbl_df", "tbl", ...); result will no longer be an S4 object

Это потому, что tidyverse не поддерживает фреймы данных S4 . Это можно обойти в нисходящем коде с помощью asS3(df). Однако пользователи моего пакета могут быть озадачены, если увидят эти предупреждения. Теперь я сталкиваюсь со следующими вариантами, и я не знаю, какой из них был бы наиболее разумным и правильным:

  • Сохраните модель S4 и надеюсь, что пользователи не будут возражать, увидев это предупреждение каждый раз они передают мои фреймы данных во что-то еще.
  • Используйте S3. Тем не менее, у меня уже есть другой класс S4, определенный в опубликованных версиях моего пакета. Я боюсь, что я бы нарушил чей-то код.
  • Смешайте S3 и S4. Это даже разрешено?

Есть ли другое решение, которое я мог бы пропустить?

1 Ответ

1 голос
/ 22 апреля 2020

Нет блестящего решения для этого, которое полностью находится под вашим контролем.

Пакет tidyverse может вызывать class<- для любого данного объекта, подобного фрейму данных, и, как вы видели, это разрушит природу S4 любого объекта. Это нельзя обойти, например, путем определения метода для coerce или вызова setAs, так как class<- не использует этот механизм. (class<- также не является универсальным c, вы не можете установить для него метод.) Единственный способ заставить tidyverse поддерживать S4 - это для автора tidyverse изменить код для использования as или похожий, и это не похоже на то, что это верхняя часть их списка дел.

Вы правы, что беспокоитесь о том, чтобы резко изменить работу вашего класса, когда вы выпустили версию своего пакет уже с классом S4.

Если:

  • ваш пакет довольно новый и еще не имеет большого количества пользователей;
  • вы можете делать все, что вам нужно делать с S3; и
  • вы не знаете другого пакета, который построил новые классы поверх вашего

, тогда может быть лучше переопределить его как S3 и добавить сообщение, когда ваш пакет установлен или загружен, чтобы сказать

спасибо за установку myPackage v2. Код может быть несовместим с v1.2 или более ранней версией; подробности см. в справке (бла)

в противном случае придерживайтесь S4.

Вы не можете точно смешать S3 и S4 для определений классов (вы можете для определений методов). Самое близкое, что вы можете получить, это setOldClass, который регистрирует класс S3 как класс S4 (тогда как вы хотели наоборот). Тем не менее, это может помочь вам достичь «вы можете делать все, что вам нужно делать с S3» выше.

Еще одна возможность - определить собственную версию class<-, которая проверяет, является ли объект класса S4 foobar пытается привести к S3 и вызывает обычный class<-, если нет. Лечение, вероятно, хуже, чем болезнь в этом случае; это замедлит все будущие преобразования класса S3 (поскольку class<- теперь является обычным вызовом функции, а не примитивом), но это должно работать в принципе. Другая причина, по которой это не рекомендуется, заключается в том, что вы не полагаетесь на то, что другой пакет выше в пути поиска делает что-то похожее (что, если другой автор пакета столкнулся с той же проблемой и захотел сделать тот же трюк? Тогда результаты будут зависеть от того, какой пакет был выше по пути search)

...