2016-08-22 3 views
2

Я хочу, чтобы выполнить data.table задачу снова и снова в вызове функции: Reduce number of levels for large categorical variables Моя проблема похожа на Data.table and get() command (R) или pass column name in data.table using variable in R, но я не могу заставить его работатьг data.table использование в вызове функции

Без вызова функции это работает просто отлично:

# Load data.table 
require(data.table) 

# Some data 
set.seed(1) 
dt <- data.table(type = factor(sample(c("A", "B", "C"), 10e3, replace = T)), 
       weight = rnorm(n = 10e3, mean = 70, sd = 20)) 

# Decide the minimum frequency a level needs... 
min.freq <- 3350 

# Levels that don't meet minumum frequency (using data.table) 
fail.min.f <- dt[, .N, type][N < min.freq, type] 

# Call all these level "Other" 
levels(dt$type)[fail.min.f] <- "Other" 

но завернутые как

reduceCategorical <- function(variableName, min.freq){ 
    fail.min.f <- dt[, .N, variableName][N < min.freq, variableName] 
    levels(dt[, variableName][fail.min.f]) <- "Other" 
} 

я только получаю ошибки как:

reduceCategorical(dt$x, 3350) 
Fehler in levels(df[, variableName][fail.min.f]) <- "Other" : 
trying to set attribute of NULL value 

А иногда

Error is: number of levels differs 
+0

Всегда лучше использовать синтаксис 'data.table' при работе с' data.table' .... –

+0

Что вы имеете в виду? 'df [, variableName] [fail.min.f]' правильный data.table, не так ли? –

+0

Нет, это не правильный способ работы с факторами. Вы можете сделать это в два этапа, но я не тестировал эффективность: 'dt [type% in% fail.min.f, type: =" Other "]; dt [, type: = factor (type)] 'Я попытаюсь придумать лучший способ, но –

ответ

3

Одна из возможностей - определить свою собственную функцию повторного выравнивания с помощью data.table::setattr, которая будет изменять dt на месте. Что-то вроде

DTsetlvls <- function(x, newl) 
    setattr(x, "levels", c(setdiff(levels(x), newl), rep("other", length(newl)))) 

Затем используйте его в другой предопределенной функции

f <- function(variableName, min.freq){ 
    fail.min.f <- dt[, .N, by = variableName][N < min.freq, get(variableName)] 
    dt[, DTsetlvls(get(variableName), fail.min.f)] 
    invisible() 
} 

f("type", min.freq) 
levels(dt$type) 
# [1] "C"  "other" 

Некоторые другие data.table альтернативы

f <- function(var, min.freq) { 
    fail.min.f <- dt[, .N, by = var][N < min.freq, get(var)] 
    dt[get(var) %in% fail.min.f, (var) := "Other"] 
    dt[, (var) := factor(get(var))] 
} 

Или с помощью set/.I

f <- function(var, min.freq) { 
    fail.min.f <- dt[, .I[.N < min.freq], by = var]$V1 
    set(dt, fail.min.f, var, "other") 
    set(dt, NULL, var, factor(dt[[var]])) 
} 

Или в сочетании с базовой R (не изменяет исходный набор данных)

f <- function(df, variableName, min.freq){ 
    fail.min.f <- df[, .N, by = variableName][N < min.freq, get(variableName)] 
    levels(df$type)[fail.min.f] <- "Other" 
    df 
} 

С другой стороны, мы могли бы придерживаться character Ср сек вместо (если type является character), вы могли бы просто сделать

f <- function(var, min.freq) dt[, (var) := if(.N < min.freq) "other", by = var] 
1

Вы ссылаетесь вещи немного по-разному в обертке, чтобы получить «типа» имя столбца используется весь variableName, которая на самом деле вектор же с получением уровней, вы не используются variableName непосредственно, как сделано в функции

Ошибка в том, что значение fail.min.f наступает NULL за счет ссылок.

+0

Я использовал dt $ x, например. все имя, чтобы предотвратить ошибку использования 'reduceCategorical ('x', 3350)', что приводит к следующей ошибке: В '[<-. data.table' (' * tmp * ',, variableName, value = c ("x", NA)): Поставляется 2 элемента, которые должны быть назначены на 3 элемента столбца 'x' (переработанные остатки, оставшиеся от 1 предмета). –

+0

В случае, если 'fail.min.f' является последним утверждением - оно не является нулевым и печатает желаемый результат. –