R-为每个列生成汇总计算,该计算依赖于因子级别的聚合

R-为每个列生成汇总计算,该计算依赖于因子级别的聚合,r,R,我有一个data.frame,其中包含大量的预测因子,每种类型的因子和一个响应/结果列。我需要为每个预测值生成一个总体度量,它是在因子聚合级别上计算的总结 我希望有人能提供一个粗略的解决方案,说明如何解决这个问题,而不必像我过去所做的那样求助于循环。 我到目前为止所做的尝试 以前我没有执行过后续的聚合,我依赖于一些非常糟糕的R代码,在这里我循环,为每列生成商品和不良品的频率表,添加商品和不良品总数,计算出贡献,然后计算出损失。这将导致每列有一个表,因此我必须再次循环,总结每个问题并将其存储在表

我有一个data.frame,其中包含大量的预测因子,每种类型的因子和一个响应/结果列。我需要为每个预测值生成一个总体度量,它是在因子聚合级别上计算的总结

我希望有人能提供一个粗略的解决方案,说明如何解决这个问题,而不必像我过去所做的那样求助于循环。

我到目前为止所做的尝试

以前我没有执行过后续的聚合,我依赖于一些非常糟糕的R代码,在这里我循环,为每列生成商品和不良品的频率表,添加商品和不良品总数,计算出贡献,然后计算出损失。这将导致每列有一个表,因此我必须再次循环,总结每个问题并将其存储在表中

从那时起,我开始使用plyr,可以对数据进行基本的总结和转换操作,但这似乎远远超出了基础

计算

Weight of Evidence (WoE) = sum ( Factor-level WoEs )
example<-data.frame(colA=factor(rep(letters[1:3],4)),
                    colB=factor(rep(letters[4:6],4)),
                    colC=factor(rep(letters[8:10],4)))

outcome<-factor(rep(c(1,0),6),labels=c("bad","good"))

wip <- as.data.frame(xtabs(formula = ~example$colA +  outcome))
wip <- dcast(wip, example.colA ~ outcome)
wip$badTotal<-sum(wip$bad)
wip$goodTotal<-sum(wip$good)
wip$badContribution<-wip$bad/wip$badTotal
wip$goodContribution<-wip$good/wip$goodTotal
wip$WOE<-log(wip$goodContribution/wip$badContribution)

outputs<-data.frame(col=c("colA"),WoE=sum(wip$WOE))
其中,每个因素水平的WoE计算为
log(好贡献/坏贡献)
贡献被定义为[商品]系数的[商品]数量/[商品]总数

单列逐步计算示例

Weight of Evidence (WoE) = sum ( Factor-level WoEs )
example<-data.frame(colA=factor(rep(letters[1:3],4)),
                    colB=factor(rep(letters[4:6],4)),
                    colC=factor(rep(letters[8:10],4)))

outcome<-factor(rep(c(1,0),6),labels=c("bad","good"))

wip <- as.data.frame(xtabs(formula = ~example$colA +  outcome))
wip <- dcast(wip, example.colA ~ outcome)
wip$badTotal<-sum(wip$bad)
wip$goodTotal<-sum(wip$good)
wip$badContribution<-wip$bad/wip$badTotal
wip$goodContribution<-wip$good/wip$goodTotal
wip$WOE<-log(wip$goodContribution/wip$badContribution)

outputs<-data.frame(col=c("colA"),WoE=sum(wip$WOE))

example下面是一个使用
data.table
的方法。请注意,我使用
keyby
outcome
对结果排序,这样以后就不会让我头疼了。还请注意,您的输入数据有一个不幸的特性,即所有条目的
WOE
为零

library(data.table)
dt = data.table(example)

totals = dt[, .N, keyby = outcome]
#   outcome N
#1:     bad 6
#2:    good 6

result = dt[, .N, keyby = list(colB, outcome)][,
              setNames(as.list(N/totals[,N]), totals[, outcome]), by = colB][,
              WOE := log(good/bad)]
result
#   colB       bad      good WOE
#1:    d 0.3333333 0.3333333   0
#2:    e 0.3333333 0.3333333   0
#3:    f 0.3333333 0.3333333   0

(由OP编辑) 要使代码在所有行上工作并返回结果的data.frame,请使用
lappy

#produce a list of results
result <- lapply(names(dt), function(colname){dt[,.N,keyby=c(colname,"outcome")][
  ,setNames(as.list(N/totals[,N]),totals[,outcome]),by=colname][
    ,WoE:=log(good/bad)][, list(colname,WoE=sum(WoE))]})

#collapse list into a data.table
rbindlist(result)
#生成结果列表

结果您能告诉我们您的样本数据的预期输出是什么吗?你的代码中有很多内容,我认为给我们一个公式和预期结果可能会有帮助。outputs保存一列的值-如果我循环遍历这些列,或者多次运行代码,但使用不同的列,我会在每次用colB替换当前列名后追加结果。很棒的eddi。这是一种对单个列进行计算的更简洁的方法-我将仔细阅读data.table文档,但您能否指出我将如何对所有列执行此操作,并为每个列存储sum(结果$WOE)?PS我知道这个例子的结果是0,但如果不是这样的话,我就不得不引入一个小代码段,在一个值中添加少量的代码,以防止0的贡献,并且不想使事情复杂化。@StephLocke只需在列名上添加一个循环:
lappy(names(dt),function(colname){dt[,.N,keyby=c(colname,“结果”)…}
Cheers@eddi,我已经根据您的评论生成了一些代码来进行转换。您可能可以生成更清晰的代码,但为了使答案完整,我已经提交了一份带有扩展名的答案编辑。请随意改进,但我会在添加代码行后将您的答案标记为答案。@StephLocke谢谢s用于编辑-我用一个更好更快的
data.table
函数替换了上一个
do.call(rbind
)。您还可以避免
结果中的几个步骤,但这具有更大的教育价值。