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
только.