Обработка отсутствующих комбинаций факторов в R
Итак, у меня есть кадр данных с двумя факторами и с одной числовой переменной:
>D
f1 f2 v1
1 A 23
2 A 45
2 B 27
.
.
.
так что уровни f1 равны 1 и 2, а уровни f2 равны A и B. В этом случае нет значения, введенного для, когда f1 = 1 и f2 = B (то есть D $V1 [D $f1 = 1 и D $f2 = B] не существует), в действительности это должно быть равным нулю.
В моем фактическом кадре данных у меня 11 уровней f1 и близко к 150 уровням f2, и мне нужно создать наблюдение с v1 = 0 для каждой комбинации f1 и f2, отсутствующей в моем кадре данных.
Как мне это сделать?
Спасибо заранее,
Ян
Ответы
Ответ 1
Использование ваших данных:
dat <- data.frame(f1 = factor(c(1,2,2)), f2 = factor(c("A","A","B")),
v1 = c(23,45,27))
одним из вариантов является создание таблицы поиска с комбинациями уровней, которая выполняется с использованием функции expand.grid()
, поставляемой с уровнями обоих факторов, как показано ниже:
dat2 <- with(dat, expand.grid(f1 = levels(f1), f2 = levels(f2)))
Затем можно выполнить операцию соединения с базами данных с помощью функции merge()
, в которой мы укажем, что все значения из таблицы поиска включены в объединение (all.y = TRUE
)
newdat <- merge(dat, dat2, all.y = TRUE)
Вышеприведенная строка дает:
> newdat
f1 f2 v1
1 1 A 23
2 1 B NA
3 2 A 45
4 2 B 27
Как вы можете видеть, недостающим комбинациям присваивается значение NA
, указывающее на отсутствие. Реально просто заменить эти NA
на 0
s:
> newdat$v1[is.na(newdat$v1)] <- 0
> newdat
f1 f2 v1
1 1 A 23
2 1 B 0
3 2 A 45
4 2 B 27
Ответ 2
Я добавляю решение tidyr
, распространяющееся с помощью fill=0
и сбор.
library(tidyr)
df %>% spread(f2, v1, fill=0) %>% gather(f2, v1, -f1)
# f1 f2 v1
#1 1 A 23
#2 2 A 45
#3 1 B 0
#4 2 B 27
Вы также можете сделать df %>% spread(f1, v1, fill=0) %>% gather(f1, v1, -f2)
.
Ответ 3
Два года спустя, но у меня была такая же проблема, и я придумал это решение plyr
:
dat <- data.frame(f1 = factor(c(1,2,2)), f2 = factor(c("A","A","B")), v1 = c(23,45,27))
newdat <- ddply(dat, .(f1,f2), numcolwise(function(x) {if(length(x)>0) x else 0.0}), .drop=F)
> newdat
f1 f2 v1
1 1 A 23
2 1 B 0
3 2 A 45
4 2 B 27