forked from lobsters/lobsters
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mod dashboard: list most-downvoted commenters by stddev
- Loading branch information
Showing
10 changed files
with
209 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Finds the consistent most-heavily-downvoted commenters. Requires downvotes to be spread over | ||
# several comments and stories because anyone can have a bad thread or a bad day. | ||
|
||
class DownvotedCommenters | ||
include IntervalHelper | ||
|
||
CACHE_TIME = 30.minutes | ||
|
||
attr_reader :interval, :period | ||
|
||
def initialize(interval) | ||
@interval = interval | ||
length = time_interval(interval) | ||
@period = length[:dur].send(length[:intv].downcase).ago | ||
end | ||
|
||
def check_list_for(showing_user) | ||
commenters[showing_user.id] | ||
end | ||
|
||
# aggregates for all commenters; not just those receiving downvotes | ||
def aggregates | ||
Rails.cache.fetch("aggregates_#{interval}", expires_in: CACHE_TIME) { | ||
ActiveRecord::Base.connection.exec_query(" | ||
select | ||
sum_downvotes, | ||
stddev(sum_downvotes) as stddev, | ||
sum(sum_downvotes) as sum, | ||
avg(sum_downvotes) as avg, | ||
avg(n_comments) as n_comments, | ||
count(*) as n_commenters | ||
from ( | ||
select | ||
sum(downvotes) as sum_downvotes, | ||
count(*) as n_comments | ||
from comments join users on comments.user_id = users.id | ||
where (comments.created_at >= '#{period}') | ||
GROUP BY comments.user_id | ||
) sums; | ||
").first.symbolize_keys! | ||
} | ||
end | ||
|
||
def stddev_sum_downvotes | ||
aggregates[:stddev] | ||
end | ||
|
||
def avg_sum_downvotes | ||
aggregates[:avg] | ||
end | ||
|
||
def commenters | ||
Rails.cache.fetch("downvoted_commenters_#{interval}", expires_in: CACHE_TIME) { | ||
rank = 0 | ||
User.active.joins(:comments) | ||
.where("comments.downvotes > 0 and comments.created_at >= ?", period) | ||
.group("comments.user_id") | ||
.select(" | ||
users.id, users.username, | ||
(sum(downvotes) - #{avg_sum_downvotes})/#{stddev_sum_downvotes} as sigma, | ||
count(distinct comments.id) as n_comments, | ||
count(distinct story_id) as n_stories, | ||
sum(downvotes) as n_downvotes") | ||
.having("n_comments > 2 and n_stories > 1 and n_downvotes >= 10") | ||
.order("sigma desc") | ||
.limit(30) | ||
.each_with_object({}) {|u, hash| | ||
hash[u.id] = { | ||
username: u.username, | ||
rank: rank += 1, | ||
sigma: u.sigma, | ||
n_comments: u.n_comments, | ||
n_stories: u.n_stories, | ||
n_downvotes: u.n_downvotes, | ||
average_downvotes: u.n_downvotes * 1.0 / u.n_comments, | ||
stddev: 0, | ||
percent_downvoted: | ||
# TODO: fix 1 + n caused by u.comments to grab total comment count | ||
u.n_comments * 100.0 / u.comments.where("created_at >= ?", period).count, | ||
} | ||
} | ||
} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<%= render partial: 'nav' %> | ||
|
||
<% if @commenters.present? %> | ||
<table class='data zebra' style='margin: 0 auto;'> | ||
<tr> | ||
<th>User</th> | ||
<th title="Number of standard deviations above average commenter">+σ</th> | ||
<th class="r" title="Downvotes per comment">D/C</th> | ||
<th class="r" title="total # of downvotes"># DV</th> | ||
<th class="r" title="total # of downvoted comments"># C</th> | ||
<th class="r" title="(percentage of all of users's comments)">% C</th> | ||
</tr> | ||
<% @commenters.each do |id, user| %><tr id="<%= user[:username] %>"> | ||
<td> | ||
<%= link_to user[:username], user_path(user[:username]) %> | ||
<small>(<%= link_to 'threads', user_threads_path(user[:username]) %>)</small> | ||
</td> | ||
<td class="r"><%= '%.1f' % user[:sigma] %></td> | ||
<td class="r"><%= '%.1f' % user[:average_downvotes] %></td> | ||
<td class="r"><%= user[:n_downvotes] %></td> | ||
<td class="r"><%= user[:n_comments] %></td> | ||
<td class="r"><%= user[:percent_downvoted].round %>%</td> | ||
</tr><% end %> | ||
<tr> | ||
<td title="Average of commenters, including the most-downvoted commenters above"> | ||
Avg of <%= @agg[:n_commenters] %> commenters | ||
</td> | ||
<td class="r" title="0 by definition; () is standard deviation"> | ||
(σ = <%= '%.1f' % @agg[:stddev] %>) | ||
</td> | ||
<td class="r"><%= '%.1f' % @agg[:avg] %></td> | ||
<td class="r"><%= (@agg[:avg] * @agg[:n_comments]).round %></td> | ||
<td class="r"><%= '%.1f' % @agg[:n_comments] %></td> | ||
</tr> | ||
</table> | ||
|
||
<% else %> | ||
<div class="nominal">🦞</div> | ||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.