R: Создание объекта S3 с отдельными внутренними и внешними именами.

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

Начнем с кадра данных:

DATE <- paste0("201", c(5,5, 6, 6))
HHWEIGHT <- c(100, 200, 100,300)
HHINCOME <-  c(30, 40, 50, 20)

STUFF <- data.frame(DATE, HHWEIGHT, HHINCOME)

Это взвешенная средняя функция, сгруппированная по дате. Он использует имена, внутренние для фрейма данных, для группировки и создания новых столбцов.

mean_dt <- function(X){
  X <- group_by(X, DATE)
  X <- mutate(X, subtot = sum(HHWEIGHT))
  X <- mutate(X, inc_wt = (HHWEIGHT * HHINCOME)/subtot)
  out <- summarize(X, mean(inc_wt))
  out
}

mean_dt(STUFF)

Применительно к кадру данных, приведенному выше, дает следующие результаты:

# A tibble: 2 x 2
    DATE `mean(inc_wt)`
  <fctr>          <dbl>
1   2015       18.33333
2   2016       13.75000

Моя цель состоит в том, чтобы после присвоения фрейма данных MyClass с помощью конструктора я мог использовать присвоенные имена внутренне в функциях класса, как если бы фрейм данных переименовывался именами (не NULL - NULL делают что-то еще) в конструкторе. Итак, после вызова этого конструктора:

MyClass <- function(X, dt=year, wt=NULL, inc=income){
  class(X) <- c("data.frame", "Myclass")
  # seeking help here
  X
}

STUFF2 <- MyClass(STUFF, dt=DATE, wt=HHWEIGHT, inc=HHINCOME)

Идея в том, что приведенный ниже метод даст тот же результат, что и mean_dt выше. Обратите внимание, что это просто функция выше, используя имена из конструктора. Обратите также внимание на то, что в своем текущем виде приведенная ниже функция не работает, потому что R, или, более конкретно, dplyr, не может найти имена, назначенные конструктором.

MyClass.mean_dt <- function(X){
  # seeking help here
  X <- group_by(X, dt)
  X <- mutate(X, subtot = sum(wt))
  X <- mutate(X, inc_wt = (wt * inc)/subtot)
  out <- summarize(X, mean(inc_wt))
  out
}

mean_dt(STUFF2)

Вопрос заключается в том, можно ли что-то добавить в конструктор и / или функции моего метода, в идеале что-то стандартизированного вида, что бы MyClass.mean_dt и другие методы работали так, как если бы объект X, здесь STUFF2, переименовал свои столбцы с помощью назначения в конструкторе. Я думаю, что это будет добавлено в одном или обоих местах, которые я пометил "Нужна помощь здесь".

Эта проблема работает при двух ограничениях. Во-первых, я хочу, чтобы пользователь мог манипулировать объектом, используя имена переменных, к которым он / она привык, которые, скорее всего, будут именами столбцов в начале. Но я хочу написать свои собственные методы, основанные на общем наборе имен, а не на уникальных именах пользователя.

Во-вторых, я не хочу достигать цели внутренней функции метода - использовать назначенные имена, копируя объект или любой большой набор столбцов. Мои объекты большие - от десяти до двадцати гигов (без сжатия) - не редкость, и назначенные столбцы обычно работают в десятках, а иногда и в сотнях. Тем не менее, я надеюсь написать программное обеспечение, которое могут использовать люди на обычных компьютерах. Поэтому мне нужно копировать до минимума.

1 ответ

Следующее является mean метод для объектов класса MyClass,

mean.MyClass <- function(X, year, wt, income){
    out <- lapply(split(X, X[[year]]), function(x){
            x[["wted"]] <- x[[wt]] * x[[income]]
            x[[paste("mean", wt, sep = ".")]] <- mean(x[["wted"]])
            x
        })
    out <- do.call(rbind, out)
    row.names(out) <- NULL
    out
}

MyClass <- function(X){
    class(X) <- c("MyClass", class(X))
    X
}

STUFF2 <- MyClass(STUFF)

mean(STUFF2, "DATE", "HHWEIGHT", "HHINCOME")
#  DATE HHWEIGHT HHINCOME wted mean.HHWEIGHT
#1 2015      100       30 3000          5500
#2 2015      200       40 8000          5500
#3 2016      100       50 5000          5500
#4 2016      300       20 6000          5500

Обратите внимание, что я не говорю, что вы не должны использовать оператор трубы. Но, кажется, хитрее заставить его распознать year как столбец X чем делать это с помощью base R только.

Другие вопросы по тегам