R函数内多重抽样问题:glm模型未使用抽样子集数据
问题分析与解决方案
嘿,我帮你找到了这个问题的根源,这其实是R里公式和数据框交互的一个常见小坑!
为什么模型会用到全部数据?
你遇到的核心问题出在公式eq1的定义方式上:你写的eq1 <- df$zeroFac ~ df$goal + df$City_Pop是直接引用了全局环境里df的整列数据,而不是用列名的形式。
当你在glm里指定data = t1时,glm会优先遵循公式里明确写的全局变量(也就是整个df的列),完全忽略data参数指定的子集t1——这就导致模型偷偷用了全部数据,而不是你拆分出来的1/4子集。
另外你的函数还有个小瑕疵:train <- data.frame(cbind(...))这种写法会把传入的列合并成数据框,但列名会变成X1、X2、X3,和你公式里的列名完全不匹配,这也加重了问题。
怎么修正?
我们需要从两个关键地方调整:
1. 改用列名定义公式
公式应该写成zeroFac ~ goal + City_Pop,只写列名,不要加df$前缀。这样glm才会去data参数指定的数据框里找对应的列,而不是直接调用全局变量。
2. 调整函数的数据传入逻辑
不要把列分开传入,直接传入整个数据框,这样函数里的train就是完整的原数据框,列名也和公式完美匹配,逻辑更清晰。
下面是修正后的完整代码:
测试数据(保持不变)
zeroFac <- c(1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1) goal <- c(8.412055, 7.528869, 8.699681, 10.478752, 9.210440, 10.308986, 10.126671, 11.002117, 10.308986, 7.090910, 10.819798, 7.824446, 8.612685, 7.601402, 10.126671, 7.313887, 5.993961, 7.313887, 8.517393, 12.611541) City_Pop <- c(11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613, 11.64613) df <- data.frame(zeroFac,goal,City_Pop)
修正后的函数与调用
forestModel <- function(eq1, data){ # 直接传入完整数据框,不用再手动合并 train <- data # 拆分数据集的逻辑不变 set.seed(123) ss <- sample(1:4, size = nrow(train), replace=TRUE, prob = c(0.25,0.25,0.25,0.25)) t1 <- train[ss==1,] # 现在glm会乖乖使用t1里的数据,因为公式用的是列名 m <- glm(eq1, family = binomial(link = 'logit'), data = t1) summary(m) } # 公式只用列名,去掉df$ eq1 <- zeroFac ~ goal + City_Pop # 调用时传入公式和完整数据框 forestModel(eq1, df)
怎么验证修正有效?
你可以在函数里加两行代码验证:
print(nrow(t1)) # 输出子集t1的行数,这里set.seed(123)后应该是5 print(nrow(model.frame(m))) # 输出模型用到的行数,应该和t1的行数一致
如果两个数字相同,就说明模型确实用了t1的数据,而不是全部数据。
额外选项:保留原传入列的方式
如果你一定要保持原来传入单独列的方式,那需要给合并后的train设置正确的列名,让它和公式匹配:
forestModel <- function(eq1, ...){ train <- data.frame(...) # 给数据框设置和公式对应的列名 colnames(train) <- c("zeroFac", "goal", "City_Pop") set.seed(123) ss <- sample(1:4, size = nrow(train), replace=TRUE, prob = c(0.25,0.25,0.25,0.25)) t1 <- train[ss==1,] m <- glm(eq1, family = binomial(link = 'logit'), data = t1) summary(m) } eq1 <- zeroFac ~ goal + City_Pop forestModel(eq1, df$zeroFac, df$goal, df$City_Pop)
不过这种方式不如直接传整个数据框清晰,容易出错,所以更推荐第一种修正方案。
内容的提问来源于stack exchange,提问作者Clinton Woods
相关产品推荐
相关产品推荐

