【问题标题】:Summarize a data.table across multiple columns跨多个列汇总 data.table
【发布时间】:2013-04-20 22:30:12
【问题描述】:

我如何summarize a data.table with unreliable data 跨多个列?

具体来说,给定

fields <- c("country","language")
dt <- data.table(user=c(rep(3, 5), rep(4, 5)),
                 behavior=c(rep(FALSE,5),rep(TRUE,5)),
                 country=c(rep(1,4),rep(2,6)),
                 language=c(rep(6,6),rep(5,4)),
                 event=1:10, key=c("user",fields))
dt
#     user behavior country language event
#  1:    3    FALSE       1        6     1
#  2:    3    FALSE       1        6     2
#  3:    3    FALSE       1        6     3
#  4:    3    FALSE       1        6     4
#  5:    3    FALSE       2        6     5
#  6:    4     TRUE       2        5     7
#  7:    4     TRUE       2        5     8
#  8:    4     TRUE       2        5     9
#  9:    4     TRUE       2        5    10
# 10:    4     TRUE       2        6     6

我想得到

#    user behavior country.name country.support language.name language.support
# 1:    3    FALSE            1             0.8             6              1.0
# 2:    4     TRUE            2             1.0             5              0.8

(这里 x.nameuser 最常见的 xx.support 是分享事件观察到这个顶部 x 的位置)

无需像这样手动检查fields

users <- dt[, sum(behavior) > 0, by=user] # have behavior at least once
setnames(users, "V1", "behavior")
dt.out <- dt[, .N, by=list(user,country)
             ][, list(country[which.max(N)],max(N)/sum(N)), by=user]
setnames(dt.out, c("V1", "V2"),  paste0("country",c(".name", ".support")))
users <- users[dt.out]
dt.out <- dt[, .N, by=list(user,language)
             ][, list(language[which.max(N)], max(N)/sum(N)), by=user]
setnames(dt.out, c("V1", "V2"),  paste0("language",c(".name", ".support")))
users <- users[dt.out]
users
#    user behavior country.name country.support language.name language.support
# 1:    3    FALSE            1             0.8             6              1.0
# 2:    4     TRUE            2             1.0             5              0.8

fields 的实际数量是 5,我想避免为每个字段分别重复相同的代码,并且如果我修改 fields,则必须编辑此函数。 请注意,this 是这个问题的实质,支持计算已向我解释elsewhere

the referenced question 一样,我的数据集大约有 10^7 行,所以我真的需要一个可扩展的解决方案;如果我能避免像users &lt;- users[dt.out] 这样的不必要的复制,那就太好了。

【问题讨论】:

  • 你能解释一下x.support的计算吗
  • @RicardoSaporta:我在support 是什么方面添加了几句话,但您必须查看引用的问题以了解更多详细信息。
  • 您可以将dt[, sum(behavior) &gt; 0, by=user] 替换为dt[,any(behavior),by=user]。您还应该解释为什么要以编程方式应用于多个列。要么你只有几列,那么它可能不值得打扰。或者你有很多列,那么最好将你的 data.table 重塑为长格式。
  • 山姆,你在这里寻求帮助,你很讨厌和粗鲁。我想知道这是否是诱使他人将时间花在您的麻烦上的最佳方式。
  • @Arun:不,英语不是我的母语。我想你是对的,那些话很粗鲁。对不起。

标签: r data.table


【解决方案1】:

这能解决您的问题吗?

fields <- c("country","language")
dt <- data.table(user=c(rep(3, 5), rep(4, 5)),
           behavior=c(rep(FALSE,5),rep(TRUE,5)),
           country=c(rep(1,4),rep(2,6)),
           language=c(rep(6,6),rep(5,4)),
           event=1:10, key=c("user",fields))

CalculateSupport <- function(dt, name) {
  x <- dt[, .N, by = eval(paste0('user,', name))]
  setnames(x, name, 'name')
  x <- x[, list(name[which.max(N)], max(N)/sum(N)), by = user]
  setnames(x, c('V1', 'V2'), paste0(name, c(".name", ".support")))
  x
}

users <- dt[, sum(behavior) > 0, by=user] 
setnames(users, "V1", "behavior")

Reduce(function(x, name) x[CalculateSupport(dt, name)], fields, users)

结果

   user behavior country.name country.support language.name language.support
1:    3    FALSE            1             0.8             6              1.0
2:    4     TRUE            2             1.0             5              0.8

附:请认真对待里卡多对您的问题的评论。 SO 到处都是愿意提供帮助的好人,但你必须善待他们并尊重他们。

【讨论】:

  • 感谢您的回答。我从不打算粗鲁,我在我的问题中看不到任何粗鲁的地方
【解决方案2】:

我不能在一个表达式中做到这一点,因为我不确定如何在 data.table 表达式中重用创建的字段。这也可能不是最有效的方法。不过,也许这将是一个很好的起点。

#Find most common country and language for each user
summ.dt<-dt[,list(behavior.summ=sum(behavior)>0,
     country.name=dt[user==.BY[[1]],.N,by=country][N==max(N),country],
     language.name=dt[user==.BY[[1]],.N,by=language][N==max(N),language]),
by=user]

#Get support for each country and language for each user
summ.dt[,c("country.support","language.support"):=list(
     nrow(dt[user==.BY[[1]] & country==country.name])/nrow(dt[user==.BY[[1]]]),
     nrow(dt[user==.BY[[1]] & language==language.name])/nrow(dt[user==.BY[[1]]])
),by=user]

    user behavior.summ country.name language.name country.support language.support
1:    3         FALSE            1             6             0.8              1.0
2:    4          TRUE            2             5             1.0              0.8

【讨论】:

  • 我的问题的重点是避免为fields 向量的每个元素使用单独的表达式
猜你喜欢
  • 2013-05-07
  • 1970-01-01
  • 1970-01-01
  • 2018-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-31
相关资源
最近更新 更多