【问题标题】:Grouping users - cumulative count by month分组用户 - 按月累积计数
【发布时间】:2015-12-08 02:17:57
【问题描述】:

我可以像这样按每个月的用户数对用户进行分组:

User.group('year(created_at)').group('month(created_at)').count
#=> {[2015, 4]=>90, [2015, 5]=>133, [2015, 6]=>131, [2015, 7]=>28, [2015, 8]=>45, [2015, 9]=>6}

我想创建统计数据,显示用户数是如何按月增长的。

所以它会返回如下内容:

{[2015, 4]=>20, [2015, 5]=>40, [2015, 6]=>55, [2015, 7]=>70, [2015, 8]=>100, [2015, 9]=>130}
# each entry is a year, month and total users count from the beginning of time by the end of this month.

我怎样才能得到想要的结果?

如果可能,我正在寻找数据库级解决方案(ActiveRecord 查询)。

欢迎提出任何建议。

【问题讨论】:

  • 请编辑解释[2015,4]=>20[2015,5]=>40 是如何计算的。将变量分配给输入哈希(例如,h = User.group(....)也很有帮助,这样给出答案的人就可以引用该变量而无需定义它。
  • @CarySwoveland 正如我在期望输出的评论中提到的,[2015,4]=>20 表示在 2015 年的第 4 个月(应用程序存在的开始)有 20 个用户在应用程序中注册,[2015,5]=>40意思是,从时间开始(2015 年第 4 个月)到第 5 个月末有 40 个用户注册,[2015, 6]=>55 表示,从时间开始到 2015 年第 6 个月末有 55 个用户注册等等,所以我有应用程序中用户数的指数统计,按月计算。
  • 安德烈,这就是我想的(按月累积用户),但我不知道所需输出的值来自哪里。例如,您是如何从90 获得20 的?另外,我不知道标题中的“指数”是什么意思,也不知道为什么所需输出中的所有值都是5 的倍数(如果不是巧合的话)。
  • 要操作的集合是User::ActiveRecord_Relation。恐怕我无法为您提供全部收藏。编辑了关于5的倍数的累积标题(我正在寻找的词,谢谢!) - 巧合:)

标签: mysql ruby-on-rails ruby database grouping


【解决方案1】:

如果g 是给定的哈希值,其中g[[y,m]]y 年、m 月份的新用户数,并且您想创建一个哈希值h,其中h[[y,m]] 是累积数y,月份m,四舍五入到最接近的5h的用户数可以计算如下:

g = {[2015, 4]=>90, [2015, 5]=>133, [2015, 6]=>131, [2015, 7]=>28,
     [2015, 8]=>45, [2015, 9]=>6}

h = g.keys.sort.each_with_object(Hash.new(0)) {|k,h| h[k]=g[k]+ h[previous(k)]}
  #=> {[2015, 4]=>90, [2015, 5]=>223, [2015, 6]=>354, [2015, 7]=>382,
  #    [2015, 8]=>427, [2015, 9]=>433} 
h.update(h) { |_,v| round_to_nearest(v, 5) }
  #=> {[2015, 4]=>90, [2015, 5]=>225, [2015, 6]=>355, [2015, 7]=>380,
  # [2015, 8]=>425, [2015, 9]=>435} 

 def previous((year, month))
  month -= 1
  (year -=1; month = 12) if month.zero?
  [year, month]
end

def round_to_nearest(n, d)
  d*(n/d.to_f).round
end

如果我误解了这个问题,请告诉我(例如,也许您打算在数据库中执行此操作)。如果是这样,我会修改或删除我的答案。

【讨论】:

  • 非常感谢!你的想法是对的,但问题是我不能在这里定义方法。是的,我打算在数据库级别(ActiveRecord 查询)进行。
  • 这可以翻译成ActiveRecord 查询吗?如果是这样,请考虑自己添加答案。 (我不熟悉ActiveRecord。)
【解决方案2】:

所以,如果我误解了什么,请纠正我。您按月注册了用户,即 1 月有 1 个用户,2 月有 2 个用户,3 月有 3 个用户,并且您想构建一个用户增长图表,因此您希望 1 月有 1 个用户,2 月有 3 个用户,3 月有 6 个用户。 如果是这种情况,您可以执行以下操作:

counts = {[2015, 4]=>1, [2015, 5]=>2, [2015, 6]=>3, [2015, 7]=>4, [2015, 8]=>5, [2015, 9]=>6}     

keys = counts.keys # save keys => [[2015, 4], [2015, 5], [2015, 6], [2015, 7], [2015, 8], [2015, 9]]

acc_values = counts.values.dup # .dup is needed if you don't want to spoil original values  
# because of for the following map! operation, 
# right now acc_values returns => [1, 2, 3, 4, 5, 6]

# use map! instead of map so we have access to already changed items, 
# while we iterating over the next
acc_values.map!.with_index { |val, key| key.zero? ? val : acc_values[key - 1] + val }    
# => [1, 3, 6, 10, 15, 21]

# build resulting hash
acc_counts = keys.zip(acc_values).to_h    
# => {[2015, 4]=>1, [2015, 5]=>3, [2015, 6]=>6, [2015, 7]=>10, [2015, 8]=>15, [2015, 9]=>21}

【讨论】:

  • 不幸的是,情况并非如此 - 我没有计数,我的目标是得到这些。请阅读我的问题下的讨论,这可能有助于澄清我的需求。
  • @AndreyDeineko 哦,看来您需要反向操作,对吧?那么,您在 1 月有 1 个,在 2 月有 3 个,在 3 月有 6 个,您希望它们回到 1、2、3 吗?
  • 您可以使用您的代码User.group('year(created_at)').group('month(created_at)').count 按月获取原始计数,并使用我的代码将它们转换为累积计数。如果你想要一个完整的 SQL 解决方案,你将不得不求助于使用变量,这可能会导致一个非常丑陋的解决方案,就像这样:stackoverflow.com/questions/17664436/…
猜你喜欢
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 2013-05-26
  • 1970-01-01
  • 2021-06-19
相关资源
最近更新 更多