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

时间:2013-07-29 15:23:11

标签: r

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

我希望有人可以提供一个粗略的解决方案来解决这个计算问题,而不像我过去那样诉诸循环。

到目前为止我尝试了什么

以前我没有进行过后续的聚合,我依靠一些非常糟糕的R代码,我循环遍历,为每列产生商品和坏的频率表,添加商品和货物。糟糕的总计,计算出贡献,然后计算WoE。这导致每列一个表,所以我必须再次循环以总结每个WoE并将其存储在表中。

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

计算

Weight of Evidence (WoE) = sum ( Factor-level WoEs )

每个因素水平WoE计算为log(goodContribution/badContribution) 和贡献定义为Number of [goods] for factor / total number of [goods]

列的逐步计算示例

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计算在示例中为0。在现实生活中,计算更复杂,因为如果它等于0,则向总数的好或坏添加一个小数字(0.0001),这样我们就不会将0或Inf传递给日志。

我已经包含了一个计算步骤,并将结果添加到输出中。以前,我会循环遍历所有列并将结果添加到输出表以获取所有WoE。为简单起见,我不希望循环结构干扰我之前编写的用于计算WoE的核心代码。

1 个答案:

答案 0 :(得分:2)

这是使用data.table的方法。请注意,我使用keybyoutcome排序结果,这让我后来不再有些头痛。另请注意,您的输入数据具有不幸的属性,导致所有条目都为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,请使用lapply

#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)