创建一个非正统的虚拟变量
Creating an unorthodox dummy variable
我需要创建一些非正统的虚拟变量,但遇到了一些麻烦。本质上,在我的数据集中,每个老师都可以教授多个 类。我正在构建一个多级数据集,因此存在重复的教师 ID 是可以的。
以下是数据示例:
#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)
如您所见,ID 为 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
我的直觉是我需要循环遍历 ID 来创建这些 ID,但过去我真的看不到实现我想要的东西的途径。
纯属娱乐,使用 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
这是一个基本的 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 会为您完成所有这些工作。
我会使用 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
您也可以使用 %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。
我需要创建一些非正统的虚拟变量,但遇到了一些麻烦。本质上,在我的数据集中,每个老师都可以教授多个 类。我正在构建一个多级数据集,因此存在重复的教师 ID 是可以的。
以下是数据示例:
#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)
如您所见,ID 为 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
我的直觉是我需要循环遍历 ID 来创建这些 ID,但过去我真的看不到实现我想要的东西的途径。
纯属娱乐,使用 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
这是一个基本的 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 会为您完成所有这些工作。
我会使用 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
您也可以使用 %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。