分组用户 - 按月累积计数

Posted

技术标签:

【中文标题】分组用户 - 按月累积计数【英文标题】: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的倍数的累积标题(我正在寻找的词,谢谢!) - 巧合:) 可能重复:***.com/questions/17664436/… 【参考方案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 解决方案,你将不得不求助于使用变量,这可能会导致一个非常丑陋的解决方案,就像这样:***.com/questions/17664436/…

以上是关于分组用户 - 按月累积计数的主要内容,如果未能解决你的问题,请参考以下文章

按月分组计数

按月分组的运行计数以汇总销售额

将按月分组的行计数为列

整个数据集的不同计数,按月分组

SQL 查询:计数,按月-年分组,具有多个日期字段

sql 按计数获取日期的博客存档格式,并按月/年分组