【问题标题】:Creating an unorthodox dummy variable创建一个非正统的虚拟变量
【发布时间】:2016-09-23 14:37:00
【问题描述】:

我需要创建一些非正统的虚拟变量,但遇到了一些麻烦。基本上在我的数据集中,每个老师都可以教授多个课程。我正在构建一个多级数据集,因此可以存在重复的教师 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 来创建这些,但过去我真的看不到实现我想要的东西的途径。

【问题讨论】:

  • 不要data.frame(cbind(x,y)),因为 cbind 会给你一个字符矩阵
  • “想要的”是否有一些规则。变量集?
  • 我怀疑它就像for (crs in levels(dat$class)) dat[crs] &lt;- ave(dat$class, dat$teacher, FUN = function(x) crs %in% x),但不幸的是ave 不合作。您可以在您的“常规”代码之后执行for (col in c("teach.ELA","teach.MATH","teach.SCIENCE")) dat[col] &lt;- ave(dat[col], dat$teacher, FUN = max),但它相当冗长。
  • @Frank 你的方式没问题,只要你强制转换为character dat$class 并将结果转换为逻辑然后转换为数字。例如as.logical(ave(as.character(dat$class.taught),dat$teacher.id,FUN=function(x) "ELA" %in% x)).
  • @nicola 好吧,不过,看起来麻烦多于其价值,嗯。

标签: r dataframe dummy-variable


【解决方案1】:

这是一个基本的 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 会为你做所有这些工作。

【讨论】:

  • 对不起,我一开始看错了。这是一个好方法,可能是base R中最好的方法。
【解决方案2】:

您也可以使用%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。

【讨论】:

    【解决方案3】:

    只是为了好玩,使用 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
    

    【讨论】:

      【解决方案4】:

      我会使用dplyrtidyr

      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
      

      【讨论】:

      • 我知道 dplyr 有办法!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 2015-05-20
      • 1970-01-01
      • 2018-04-06
      • 2020-01-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多