Арифметические операции над R факторами

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

Ответ 1

Если вы действительно хотите, чтобы уровни фактора были использованы, вы либо делаете что-то очень неправильное или слишком умное для своего же блага.

Если то, что у вас есть, является фактором, содержащим числа, хранящиеся в уровнях фактора, то вы хотите сначала принудительно его перенести в числовое значение, используя as.numeric(as.character(...)):

dat <- data.frame(f=as.character(runif(10)))

Вы можете увидеть разницу между доступом к индексам факторов и присвоением содержимого фактора здесь:

> as.numeric(dat$f)
 [1]  9  7  2  1  4  6  5  3 10  8
> as.numeric(as.character(dat$f))
 [1] 0.6369432 0.4455214 0.1204000 0.0336245 0.2731787 0.4219241 0.2910194
 [8] 0.1868443 0.9443593 0.5784658

Сроки против альтернативного подхода, который только делает преобразование на уровнях, показывает его быстрее, если уровни не уникальны для каждого элемента:

dat <- data.frame( f = sample(as.character(runif(10)),10^4,replace=TRUE) )
library(microbenchmark)
microbenchmark(
  as.numeric(as.character(dat$f)),
  as.numeric( levels(dat$f) )[dat$f] ,
  as.numeric( levels(dat$f)[dat$f] ),
  times=50
  )

                              expr     min      lq  median      uq     max
1  as.numeric(as.character(dat$f)) 7835865 7869228 7919699 7998399 9576694
2 as.numeric(levels(dat$f))[dat$f]  237814  242947  255778  270321  371263
3 as.numeric(levels(dat$f)[dat$f]) 7817045 7905156 7964610 8121583 9297819

Поэтому, если length(levels(dat$f)) < length(dat$f), используйте as.numeric(levels(dat$f))[dat$f] для значительного увеличения скорости.

Если length(levels(dat$f)) приблизительно равно length(dat$f), коэффициент усиления отсутствует:

dat <- data.frame( f = as.character(runif(10^4) ) )
library(microbenchmark)
microbenchmark(
  as.numeric(as.character(dat$f)),
  as.numeric( levels(dat$f) )[dat$f] ,
  as.numeric( levels(dat$f)[dat$f] ),
  times=50
  )

                              expr     min      lq  median      uq      max
1  as.numeric(as.character(dat$f)) 7986423 8036895 8101480 8202850 12522842
2 as.numeric(levels(dat$f))[dat$f] 7815335 7866661 7949640 8102764 15809456
3 as.numeric(levels(dat$f)[dat$f]) 7989845 8040316 8122012 8330312 10420161

Ответ 2

Вы можете определить своих собственных операторов для этого, см. ? Arith. Без групповых дженериков вы можете определить свои собственные бинарные операторы% operator%:

%-% <- function (factor1, factor2){
  # put in the code here to calculate difference 
  # of two factors (e.g. facor1 level cat - factor2 level mouse = ?)
}

Ответ 3

Вы должны дважды проверить, как вы сначала извлекаете данные. Если это действительно числовые столбцы, то R должен распознать это (иногда иногда испортится Excel). В любом случае, это может быть вызвано фактором, потому что в столбцах есть другие нежелательные элементы. Ответы, которые вы получили до сих пор, не упомянули, что as.numeric() только возвращает номера уровней. Это означает, что вы не будете выполнять операцию над фактическими числами, которые были преобразованы в факторы, а номерами уровней, связанными с каждым фактором.

Ответ 4

Вам нужно будет преобразовать коэффициенты в числовые массивы.

a <- factor(c(5,6,5))
b <- factor(c(3,2,1))
df <- data.frame(a, b)

# WRONG: Factors can't be subtracted.
df$a - df$b

# CORRECT: Get the levels and substract
as.numeric(levels(df$a)[df$a]) - as.numeric(levels(df$b)[df$b])