2016-05-25 5 views
2

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

Вот пример данных:

#generate data 
teacher.id <- c(1:5, 1:5) 
class.taught <- c("ELA", "Math", "Science", "ELA", "Math", "Science", "Math", "ELA", "ELA", "Math") 

# combine into data frame 
dat <- data.frame(teacher.id, class.taught) 

Как вы можете видеть учителей с идентификаторами 1 и 3 и преподающих 2 разных классов.

Традиционный подход к созданию выходов фиктивных переменных:

# example of what I have done so far 
dat$teach.ELA <- ifelse(dat$class.taught == "ELA", 1, 0) 
dat$teach.MATH <- ifelse(dat$class.taught == "Math", 1, 0) 
dat$teach.SCIENCE <- ifelse(dat$class.taught == "Science", 1, 0) 
dat 

Однако здесь, как я хотел бы, чтобы новые фиктивные переменные посмотреть:

desired.ELA <- c(1,0,1,1,0,1,0,1,1,0) 
desired.MATH <- c(0,1,0,0,1,0,1,0,0,1) 
desired.SCIENCE <- c(1,0,1,0,0,1,0,1,0,0) 
dat.2 <- data.frame(dat, desired.ELA, desired.MATH, desired.SCIENCE) 
dat.2 

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

+1

Не 'data.frame (cbind (x, y))', поскольку cbind даст вам матрицу символов – Frank

+0

Есть ли какое-то правило для «желаемого». множество переменных? – lmo

+1

Я подозреваю, что это как 'для (crs в уровнях (dat $ class)), что [crs] <- ave (dat $ class, dat $ teacher, FUN = function (x) crs% in% x)', но, к сожалению, ave' не сотрудничает. Вы можете сделать «для (col in c (« learn.ELA »,« learn.MATH »,« learn.SCIENCE »)), что [col] <- ave (dat [col], dat $ teacher, FUN = max) 'после вашего« обычного »кода, но он довольно длинный. – Frank

ответ

4

Вот базовый метод R. Идея заключается в том, что вы создаете переменные для каждого учителя, а затем объединить их на исходные данные:

# get dummies for each teacher 
temp <- as.data.frame(with(dat, table(teacher.id, class.taught) > 0)) 
temp$teacher.id <- as.integer(row.names(temp)) 

# merge onto dataset 
merge(dat, temp, by="teacher.id") 

Вы могли насиловать логические выражения в целое число, если это действительно прослушивают Вас, но R будет делать всю эту работу за вас.

+1

Извините, я изначально неправильно понял. Это хороший способ, возможно, лучший способ в базе R. – Frank

+2

@Frank Иногда некоторые знания Stata окупаются ... – lmo

2

Просто для удовольствия, используя dplyr:

library(dplyr) 
dat %>% left_join(
    dat %>% 
     group_by(teacher.id) %>% 
     summarize(desired.ELA = ifelse(sum(teach.ELA), 1, 0), 
     desired.MATH = ifelse(sum(teach.MATH), 1, 0), 
     desired.SCIENCE = ifelse(sum(teach.SCIENCE), 1, 0)) 
) 

Выход:

teacher.id class.taught teach.ELA teach.MATH teach.SCIENCE desired.ELA desired.MATH desired.SCIENCE 
1   1   ELA   1   0    0   1   0    1 
2   2   Math   0   1    0   0   1    0 
3   3  Science   0   0    1   1   0    1 
4   4   ELA   1   0    0   1   0    0 
5   5   Math   0   1    0   0   1    0 
6   1  Science   0   0    1   1   0    1 
7   2   Math   0   1    0   0   1    0 
8   3   ELA   1   0    0   1   0    1 
9   4   ELA   1   0    0   1   0    0 
10   5   Math   0   1    0   0   1    0 
1

Я бы использовал dplyr и tidyr.

library(dplyr) 
library(tidyr) 

dummies <- 
dat %>% 
    group_by(teacher.id, class.taught) %>% 
    summarise(is_taught = as.numeric(n() > 0)) %>% 
    spread(class.taught, is_taught, fill = 0) 

> dummies 
Source: local data frame [5 x 4] 

    teacher.id ELA Math Science 
     (int) (dbl) (dbl) (dbl) 
1   1  1  0  1 
2   2  0  1  0 
3   3  1  0  1 
4   4  1  0  0 
5   5  0  1  0 

Затем вы можете использовать их в исходных данных с помощью соединения.

> inner_join(dat, dummies) 
Joining by: "teacher.id" 
    teacher.id class.taught ELA Math Science 
1   1   ELA 1 0  1 
2   2   Math 0 1  0 
3   3  Science 1 0  1 
4   4   ELA 1 0  0 
5   5   Math 0 1  0 
6   1  Science 1 0  1 
7   2   Math 0 1  0 
8   3   ELA 1 0  1 
9   4   ELA 1 0  0 
10   5   Math 0 1  0 
+0

Я знал, что есть способ с dplyr! – bfoste01

3

Вы также можете сделать это с помощью %in%:

dums <- function(dt, x){ 
    ix <- dt[, 2] %in% x 
    dt[, 1] %in% unique(dt[ix, 1]) 
} 

dums(dat, 'ELA') 
dums(dat, 'Math') 
dums(dat, 'Science') 

Это дает TRUE/FALSE, а не 0/1 векторов, но as.integer преобразует их в 0/1 в случае необходимости.