【问题标题】:Summarize a data.table with unreliable data用不可靠的数据总结一个 data.table
【发布时间】:2013-04-24 19:43:51
【问题描述】:

我有一个记录事件的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 毕竟)。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    另一种方式:

    已编辑。 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
    

    【讨论】:

    • 这非常慢(并生成“命名向量”性能说明)
    • 已编辑。 table 是问题所在。现在它在我的笔记本电脑上的 1e6 行 data.table 上运行不到 1 秒。对于未来,了解问题的实际规模会很有用。 named vector 是一条消息,通常似乎根本不会影响性能。你可以检查一下。我已经删除了这里的名字。 如果你能努力找出慢的问题并报告回来,而不是仅仅说非常慢,那就太好了。
    • 对于未来,您提出的问题不是如何优化这个?,而是如何做到这一点? .此外,您没有提到数据的大小,您的示例也没有显示它。期望显示如何做到这一点的 a 解决方案是正常的,不一定是优化的解决方案。使用数据进行测试肯定有助于编写更好的代码。
    • 您的解决方案并不比@eddi 的解决方案快,而他使用排序而您却没有。我想我的组足够小,以至于日志无关紧要。
    • @sds,在我的基准测试中,正如我在他的评论中提到的那样(在 1e6 行上),它的速度提高了 0.5
    【解决方案2】:

    使用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]
    

    【讨论】:

    • 是来自plyr 包的count
    • 哈哈,是的! :) 我只是输入了count(country) 而没有检查它在我的环境中来自哪里,因为这就是我所说的执行此操作的函数 - 它有效:)
    • count 也很慢(就像我使用table 的旧解决方案一样)。使用data.table 分组(您的第二个解决方案)要快得多。完全删除第一个解决方案可能更好。通过查看优化消息,您可以进一步改进(它在 1.55 秒内运行,而我在 1e6 行测试中的运行时间为 1 秒)。
    • 我认为你不需要使用order
    • @sds,你会的。试试这个:dt[order(user,-country)][, list(freq=.N), by = list(user, country)] 看看为什么
    猜你喜欢
    • 2020-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-06-24
    • 2013-01-14
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多