【问题标题】:lapply with anonymous function call to svytable results in object 'x' not foundlapply 对 svytable 的匿名函数调用导致找不到对象“x”
【发布时间】:2014-07-29 02:43:08
【问题描述】:

我有一个正在为其创建列联表的调查数据集。数据框中的每一列都是一个问题,一般来说,问题倾向于组合在一起。所以为了让生活更轻松,我一直在使用 lapply 循环遍历部分并使用以下代码返回列联表:

> out <- lapply(dat[,162:170], function(x) round(prop.table(table(x,dat$seg_2),2),3)*100)
> out
$r3a_1
            
x               1    2
  Don't Know  1.9  1.4
  No         14.2  4.9
  Yes        83.9 93.7

$r3a_2
            
x               1    2
  Don't Know  2.7  1.7
  No         14.8  6.6
  Yes        82.4 91.6

etc...

如您所见,我正在遍历第 162:170 列并创建一个道具表,显示第 1 组和第 2 组之间的不同响应。

但是,我想对这些数据进行加权。所以我正在使用调查包创建一个名为 dat_weight 的简单加权调查设计对象,并使用 svytable() 而不是 table()。我可以手动在单个列上运行更新的代码:

> round(prop.table(svytable(~dat[,162] + dat$seg_2, dat_weight),2),3)*100 
            dat$seg_2
dat[, 162]      1    2
  Don't Know  2.5  2.7
  No         16.5  5.4
  Yes        80.9 91.9

但是,当我尝试使用 lapply 时,它不起作用:

> out <- lapply(dat[,162:170], function(x) round(prop.table(svytable(~x + dat$seg_2, dat_weight),2),3)*100)

Error in eval(expr, envir, enclos) : object 'x' not found 

显然,匿名函数调用和 svytable 不能很好地配合使用。我尝试创建一个也不起作用的 for 循环。我猜这与范围界定有关,但我不知道如何解决它。

当然,必须有一种方法可以循环遍历该调查的各个部分,并且避免为每一列创建唯一的代码行。任何帮助将不胜感激。

编辑以添加一些示例数据:

> library("survey")
> dat <- structure(list(r3a_1 = structure(c(3L, 2L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("Don't Know", 
"No", "Yes"), class = "factor"), r3a_2 = structure(c(3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L), .Label = c("Don't Know", "No", "Yes"), class = "factor"), 
    r3a_3 = structure(c(3L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L), .Label = c("Don't Know", 
    "No", "Yes"), class = "factor"), r3a_4 = structure(c(3L, 
    2L, 2L, 2L, 3L, 2L, 2L, 3L, 3L, 2L, 2L, 3L, 2L, 3L, 2L, 2L, 
    3L, 3L, 3L, 1L), .Label = c("Don't Know", "No", "Yes"), class = "factor"), 
    r3a_5 = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 3L, 2L, 
    2L, 3L, 2L, 3L, 3L, 2L, 3L, 2L, 3L, 1L), .Label = c("Don't Know", 
    "No", "Yes"), class = "factor"), r3a_6 = structure(c(3L, 
    3L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 2L, 3L, 3L, 2L, 2L, 2L, 3L, 
    2L, 3L, 3L, 3L), .Label = c("Don't Know", "No", "Yes"), class = "factor"), 
    r3a_7 = structure(c(1L, 2L, 2L, 2L, 3L, 2L, 2L, 3L, 3L, 2L, 
    3L, 3L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L), .Label = c("Don't Know", 
    "No", "Yes"), class = "factor"), r3a_8 = structure(c(3L, 
    2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 2L, 3L, 3L, 2L, 3L, 3L, 2L, 
    2L, 2L, 3L, 3L), .Label = c("Don't Know", "No", "Yes"), class = "factor"), 
    r3a_9 = structure(c(1L, 3L, 2L, 2L, 3L, 2L, 2L, 3L, 3L, 3L, 
    3L, 3L, 2L, 2L, 2L, 3L, 2L, 2L, 3L, 3L), .Label = c("Don't Know", 
    "No", "Yes"), class = "factor"), weight = c(0.34, 0.34, 0.34, 
    0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.43, 
    0.43, 0.43, 0.34, 0.34, 0.34, 0.34, 0.34), seg_2 = structure(c(1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L), .Label = c("1", "2"), class = "factor")), .Names = c("r3a_1", 
"r3a_2", "r3a_3", "r3a_4", "r3a_5", "r3a_6", "r3a_7", "r3a_8", 
"r3a_9", "weight", "seg_2"), row.names = c(NA, 20L), class = "data.frame")

> dat_weight <- svydesign(ids = ~1, weights = ~weight, data = dat)

从那里你可以得到加权和未加权的表格:

round(prop.table(table(dat[,1],dat$seg_2),2),3)*100  #unweighted

round(prop.table(svytable(~dat[,1] + dat$seg_2, dat_weight),2),3)*100   #weighted

但是,这是可行的:

lapply(dat[,1:9], function(x) round(prop.table(table(x,dat$seg_2),2),3)*100)

虽然不是这样:

lapply(dat[,1:9], function(x) round(prop.table(svytable(~x + dat$seg_2, dat_weight),2),3)*100)

【问题讨论】:

  • 如果您能提供一个样本数据集来测试可能的解决方案,这将更容易提供帮助。当您使用公式语法时,通常您实际上不会传入向量,通常会从 data.frame 传入变量名称。我猜你可以为svytable 提供一个data= 参数,然后让公式起作用。见how to make a reproducible example
  • 嗨,我刚刚用一些重现问题的数据编辑了帖子。编辑:data= 参数包含在设计对象 dat_weight 中。
  • 完美。这使得提供帮助变得更加容易,这就是为什么当有人提出问题时我们几乎总是要求提供可重复的示例。

标签: r


【解决方案1】:

好吧,看来svytable 函数很挑剔,只会在设计对象中查找数据。它似乎没有在封闭环境中寻找x。因此,另一种方法是动态构建公式。因此,我们不是传入数据列本身,而是从 data.frame 中传入列名。然后我们将它们代入公式,然后它们由指向原始 data.frame 的设计对象解析。这是使用您的示例数据的一些工作代码

lapply(names(dat)[1:9], function(x) round(prop.table(
    svytable(bquote(~.(as.name(x)) + seg_2), dat_weight),
2),3)*100)

所以这里我们使用bquote 来构建公式。 .() 允许我们插入表达式,在这里我们获取x 中的字符值并将其转换为专有名称对象。因此从"r3a_9" 变为r3a_9

【讨论】:

  • 太棒了。非常感谢。我从没想过要自己传递svytable 的名字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多