使用不可靠的数据对data.table进行汇总

3

我有一个事件记录的 data.table,记录用户ID、居住国家和事件。例如:

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

如您所见,数据有些损坏:事件5报告用户3在国家2(或者他旅行了-这对我来说无关紧要)。

因此当我试图汇总数据时:

dt[, country[.N] , by=user]
   user V1
1:    3  2
2:    4  2

我得到了用户3的错误国家信息。 理想情况下,我希望能够获取用户最常访问的国家以及他在那里度过的时间百分比:

   user country support
1:    3       1     0.8
2:    4       2     1.0

我该如何做到这一点?

实际数据有约10^7行,因此解决方案必须能够扩展(这就是为什么我使用data.table而不是data.frame的原因)。

2个回答

7

另一种方法:

已经进行了编辑。table(.) 是罪魁祸首。将其更改为完整的data.table语法。

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"), c("country", "support"))
#    user country support
# 1:    3       1     0.8
# 2:    4       2     1.0

这个速度非常慢(并生成了“命名向量”性能提示)。 - sds
编辑过了。问题出在 table 上。现在在我的笔记本上,对于 1e6 行数据表,运行时间不到 1 秒。将来,了解您的问题的实际大小会很有用。named vector 是一条消息,通常不会对性能产生太大影响。您可以检查一下。我已经在这里删除了名称。如果您能花些功夫找到缓慢的问题并报告回来,而不仅仅是说“非常慢”,那就太好了。 - Arun
对于未来,您提出的问题不是“如何优化这个?”而是“如何做到这一点?”此外,您没有提及数据的大小,您的示例也没有显示它。只需要期望一个解决方案来展示如何做到这一点,而不一定是最优化的解决方案。使用数据进行测试确实有助于编写更好的代码。 - Arun
你的解决方案并不比@eddi的更快,尽管他使用了排序而你没有。我猜我的分组足够小,日志对速度影响不大。 - sds
@sds,在我的基准测试中,它比我在评论中提到的要快0.5秒(在100万行上)。 - Arun
显示剩余3条评论

4
使用plyrcount函数:
dt[, count(country), by = user][order(-freq),
                                list(country = x[1],
                                     support = freq[1]/sum(freq)),
                                by = user]
#   user country support
#1:    4       2     1.0
#2:    3       1     0.8

思路是统计每个用户所在的国家数量,按照最高频率排序,然后获取需要的数据。

感谢 @mnel 提供的更聪明的答案,它不使用额外的函数:

dt[, list(freq = .N),
     by = list(user, country)][order(-freq),
                               list(country = country[1],
                                    support = freq[1]/sum(freq)),
                               by = user]

1
count 函数是来自于 plyr 包吗? - Arun
哈哈,是的! :) 我只是在不检查来自环境的计数(国家)函数的情况下输入了 count(country),因为这就是我称呼执行此操作的函数方式 - 并且它起作用了 :) - eddi
count 也很慢(就像我以前使用 table 的解决方案一样)。使用 data.table 分组(您的第二个解决方案)要快得多。最好完全删除第一个解决方案。通过查看优化消息,可以进一步改进您的解决方案(在我的 1e6 行测试中,它运行了 1 秒,而您的运行时间为 1.55 秒)。 - Arun
我认为你不需要使用order - sds
@sds 好的,我猜你是说Arun的解决方案更有效率,我同意。 - eddi
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接