首页 > 解决方案 > 基于lm规范在数据集中自动创建变量

问题描述

我有一个如下所示的数据集:

outcome <- c(1,2, 2, 1, 2, 2, 2, 1)
city <- rep(c("A", "B"),4)
year <- c(2000, 2001, 2000, 2000, 2000, 2001, 2001, 2000)
educ <- c("high", "low", "low", "low", "high", "high", "high", "low")
age <- c(25,35, 30, 29, 31, 40, 20, 23)
area <- c("city", "sub", "sub", "sub", "city", "city", "city", "city")
peopleinhouse <- c(2,4, 3, 3, 5, 2, 1, 2)
adataset <- data.frame(outcome, city, year, educ, age, area, peopleinhouse, stringsAsFactors = FALSE)

我有一个向量如下:

avector <- c("outcome", "as.factor(city)", "year", "as.factor(educ):age", "log(age)", "as.factor(area):peopleinhouse")

我想自动化创建新(交互)变量的过程,avectoradataset作为输入和anotherdataset输出。

我开始如下:

avector <- unlist(strsplit(avector , split=':', fixed=TRUE))

for (i in 1:length(avector)) {
  if (substr(avector[i], start = 1, stop = 9) == "as.factor") {
    adataset[,i] <- as.factor(adataset[,i])
  } else if(substr(avector[i], start = 1, stop = 3) == "log") {
      adataset[,i] <- log(adataset[,i])
  } else if (substr(avector [i], start = 1, stop = 1) == "I") {
      # Assumes a quadratic
      adataset[,i] <- adataset[,i]*adataset[,i]
  }
}

(这应该适用于单个变量(适用于我的实际数据),但我Error in Math.factor(adataset[, i]) : ‘log’ not meaningful for factors在示例中得到错误)

但我不确定如何自动处理交互条款。

由于ivmodel来自 library ,我需要交互项是一个变量ivmodel

所需的输出将是一个数据集,其中包含交互项作为变量:

as.factor(educ):ageas.factor(area):peopleinhouse作为一个变量。

有任何想法吗?

编辑:

我目前正朝着以下方向前进:

# For every entry in the vector
for (i in 1:length(avector)) {
# if there is a ":" in the entry
    if (grepl(":", avector[i], fixed = FALSE)) {
# split the string into two string
        tmp <- unlist(strsplit(avector[i], split=':', fixed=FALSE))
# make a new variable
        adataset[,(length(avector)+i)] <- adataset[,tmp[1]]*adataset[,tmp[2]]
# Change the name of the new variable
        names(adataset[,(length(avector)+i)]) <- paste0(names(tmp[1]), names(tmp[2]))
    }
}

但是我无法正确使用语法..

编辑二:

ivmodelFormula@Edo 在接受公式的评论中指出。这消除了我的部分问题。然而?ivmodelFormula 表明,对于多种工具,这些工具仍然由 (a) 向量提供:

# Multiple instruments
Z = card.data[,c("nearc4","nearc2")]
card.model2IV = ivmodelFormula(lwage ~ educ + exper + expersq + black + 
                                south + smsa + reg661 + 
                                reg662 + reg663 + reg664 + 
                                reg665 + reg666 + reg667 + 
                                reg668 + smsa66 | nearc4 + nearc2 +
                                exper + expersq + black + 
                                south + smsa + reg661 + 
                                reg662 + reg663 + reg664 + 
                                reg665 + reg666 + reg667 + 
                                reg668 + smsa66,data=card.data)
card.model2IV

例如,假设我想运行:

require(ivmodel)
Z <- adataset[, c("area", "educ", "peopleinhouse") ]
card.model2IV = ivmodelFormula(outcome ~ log(age) + as.factor(city) + year | area + educ + as.factor(city) + year)
card.model2IV

这样可行..

但是,如果我想以area:educ交互方式运行,例如:

require(ivmodel)
Z <- adataset[, c("area", "educ", "peopleinhouse")]
another_card.model2IV = ivmodelFormula(outcome ~ log(age) + as.factor(city) + year | area:educ+ as.factor(city) + year)
another_card.model2IV

它运行,但它给了我与 相同的输出card.model2IV,所以我仍然必须与数据中的工具进行交互。

标签: rsubsetformula

解决方案


为了总结我们在评论中的讨论,我将给出最终答案。希望对其他将要查找此内容的用户有用。

答案分为三部分:第一部分与第一个问题的解决方案有关,第二部分与@Tom面临的实际问题有关,第三部分与使用其他包完成@Tom的有关实际目标。


第一部分

最初,问题是在给定初始数据集和字符串向量的情况下自动创建具有特定交互和转换的数据集。

解决问题的好方法是model.matrix按照@krfurlong 的建议使用。

例如以这种方式。

给定以下数据:

outcome <- c(1,2, 2, 1, 2, 2, 2, 1)
city <- rep(c("A", "B"),4)
year <- c(2000, 2001, 2000, 2000, 2000, 2001, 2001, 2000)
educ <- c("high", "low", "low", "low", "high", "high", "high", "low")
age <- c(25,35, 30, 29, 31, 40, 20, 23)
area <- c("city", "sub", "sub", "sub", "city", "city", "city", "city")
peopleinhouse <- c(2,4, 3, 3, 5, 2, 1, 2)
adataset <- data.frame(outcome, city, year, educ, age, area, peopleinhouse, stringsAsFactors = FALSE)


avector <- c("outcome", "as.factor(city)", "year", "as.factor(educ):age", "log(age)", "as.factor(area):peopleinhouse")

您可以通过以下方式实现您的目标:

make_formula <- function(vec){
    
    x <- paste(vec[-1], collapse = " + ")
    frm <- paste(vec[1], x, sep = " ~ ")
    as.formula(frm)
    
}

as.data.frame(model.matrix(make_formula(avector), adataset))
  (Intercept) as.factor(city)B year log(age) as.factor(educ)high:age as.factor(educ)low:age as.factor(area)city:peopleinhouse as.factor(area)sub:peopleinhouse
1           1                0 2000 3.218876                      25                      0                                 2                                0
2           1                1 2001 3.555348                       0                     35                                 0                                4
3           1                0 2000 3.401197                       0                     30                                 0                                3
4           1                1 2000 3.367296                       0                     29                                 0                                3
5           1                0 2000 3.433987                      31                      0                                 5                                0
6           1                1 2001 3.688879                      40                      0                                 2                                0
7           1                0 2001 2.995732                      20                      0                                 1                                0
8           1                1 2000 3.135494                       0                     23                                 2                                0

第二部分

最终,我们发现@Tom 的实际目标是运行带有 package.json 的特定模型ivmodel

解决此问题的最佳方法是使用ivmodel调用的本机函数,该函数ivmodelFormula允许您设置处理转换和交互的公式。

例如以这种方式。

library(ivmodel)

card.model2IV <- ivmodelFormula(outcome ~ log(age) + as.factor(city) + year | area + educ + as.factor(city) + year)

another_card.model2IV <- ivmodelFormula(outcome ~ log(age) + as.factor(city) + year | area:educ+ as.factor(city) + year)

尽管在这种特定情况下打印的输出可能看起来相同,但可以注意到all.equal(card.model2IV, another_card.model2IV)并非如此TRUE,具体而言card.model2IV$Zanother_card.model2IV$Z看起来与预期的一样。

card.model2IV$Z

#> 8 x 2 sparse Matrix of class "dgCMatrix"
#>   areasub educlow
#> 1       .       .
#> 2       1       1
#> 3       1       1
#> 4       1       1
#> 5       .       .
#> 6       .       .
#> 7       .       .
#> 8       .       1


another_card.model2IV$Z

#> 8 x 4 sparse Matrix of class "dgCMatrix"
#>   areacity.educhigh areasub.educhigh areacity.educlow areasub.educlow
#> 1                 1                .                .               .
#> 2                 .                .                .               1
#> 3                 .                .                .               1
#> 4                 .                .                .               1
#> 5                 1                .                .               .
#> 6                 1                .                .               .
#> 7                 1                .                .               .
#> 8                 .                .                1               .

第三方

最后,我们发现该包不处理多个插桩变量。

看到我不是该主题的专家,如果其他用户对此有更多了解,他们可能会随时更新此答案以使其更有用。

还有其他包可以处理这种模型。

查看:


推荐阅读