cohort_me 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,33 +1,160 @@
1
- # CohortMe
1
+ # Cohort analysis - User retention in a Rails application.
2
2
 
3
- Provides tools to Ruby and Rails developers to perform cohort analysis.
3
+ I want my actions to be more data-driven. I want to make Dave McClure, Steve Blank, and Eric Ries proud. But, it's easier said than done.
4
4
 
5
+ Analytics are still a pain in the ass.
5
6
 
6
- ## Installation
7
+ How can I tell if people are using my product, [Draft](https://draftin.com/)? ([Draft is the tool I'm working on to help people become better writers](http://ninjasandrobots.com/draft-version-control-for-writing).)
7
8
 
8
- Add this line to your application's Gemfile:
9
+ I could look at user retention. Once people start using Draft, do they come back to use it again?
9
10
 
10
- gem 'cohort_me'
11
+ There's some great software to help study how users return to your product. They use a method called cohort analysis, which breaks up users into groups of people who "activate" or sign-up at the same time and then you track their progress as a group. Do users that signup in January after one month use your app more than those users who signed up in December after their first month? They do? Awesome, those features and things you did in February might be onto something.
11
12
 
12
- And then execute:
13
+ To use these analytics tools, I have to integrate my application with them. I have to figure out how to send even more data to them.
13
14
 
14
- $ bundle
15
+ But I don't want to integrate something else right now. I already have data. It's coming out of my ears. A database full of it. Log files upon log files. Can't some of the data I already have power this user retention analysis? Do I really have to start all over again collecting new data?
15
16
 
16
- Or install it yourself as:
17
+ I don't want to work harder for more data right now. I want the data to work harder for me.
17
18
 
18
- $ gem install cohort_me
19
+ I got irritated, so I built a simple way to study your Rails app's user retention using a cohort analysis with the data you already have in your database. It's called CohortMe.
19
20
 
20
- ## Usage
21
+ [https://github.com/n8/cohort_me](https://github.com/n8/cohort_me)
21
22
 
23
+ To get a cohort analysis, just use this in your Rails app:
22
24
 
23
- Help's you do a cohort analysis of user retention in a Rails app.
25
+ ```ruby
26
+ CohortMe.analyze(activation_class: Document)
27
+ ```
24
28
 
29
+ That's it.
25
30
 
31
+ Above is an example of studying user retention for Draft. Users are "activated" once they create their first Document. Then they "return" if they create another Document.
32
+
33
+ CohortMe.analyze will spit out a ruby Hash:
34
+
35
+ ```ruby
36
+ {Mon, 21 Jan 2013=>{:count=>[15, 1, 1, 0], :data=>[#<Document user_id: 5, created_at: "2013-01-22 18:09:15">,
37
+ ```
38
+
39
+ During the week starting on 21 Jan 2013, I had 15 people signup. One week later, I only had 1 user still creating Documents. Yuck. That's a terrible retention rate. I better explore why they aren't coming back. **Note:** it's just bogus test data.
40
+
41
+ [Here's some partial view code you can use](https://raw.github.com/n8/cohort_me/master/lib/cohort_me/_cohort_table.html.erb) to show your cohort analysis in a nice table:
42
+
43
+ ![](http://i.imgur.com/qBbkZv8.png)
44
+
45
+ Pretty easy. If you have any trouble let me know on [Twitter](https://twitter.com/natekontny) or email.
46
+
47
+
48
+
49
+ CohortMe Details
50
+ ----------------
51
+
52
+ Options you can pass to CohortMe.analyze:
53
+
54
+ * `:period` - Default is "weeks". Can also be "months" or "days".
55
+ * `:activation_class` - The Rails model class that CohortMe will query to find activated users. For example: User. CohortMe will look for a created_at timestamp in this table.
56
+ * `:activation_user_id` - Default is "user_id". Most Rails models are owned by a User through a "user_id". If it's something else like "owner_id", you can override that here.
57
+ * `:activation_conditions` - If you need anything fancy to find activated users. For example, if your acivation_class is Document (meaning find activated Users who have created their first Document) you could pass in: `:activation_conditions => ["(content IS NOT NULL && content != '')]`, which means: Find activated Users who have create their first Document that has non-empty content.
58
+ * `:activity_class` - Default is the same class used as the activation_class. However, is there a different Class representing an Event the user creates in your database when they revisit your application? Do you expect users to create a new Message each week? Or a new Friend?
59
+ * `:activity_user_id` - Defaults to "user_id".
60
+
61
+
62
+ Examples
63
+ ---------
64
+
65
+ First, figure out who your activated users are. Are they simply Users in your database? Could be. But I prefer treating an active user as someone who has signed up AND done a key feature.
66
+
67
+ For example, if you created a group messaging app, it's probably a User when they created their first Group.
68
+
69
+ Next, figure out what a user does to be classified as "returning". This needs to be another record in your database. Is it a Message they made this week? A Share? A new Document?
70
+
71
+ For my group messaging tool, my cohort analysis might look like this:
72
+
73
+ ```ruby
74
+ @cohorts = CohortMe.analyze(period: "months",
75
+ activation_class: Group,
76
+ activity_class: Message)
77
+ ```
78
+
79
+ CohortMe will look at Groups to find activated users: people who created their first Group. Next, CohortMe will look to the Message model to find out when those users have returned to my app to create that Message activity.
80
+
81
+ This assumes a Group belongs to a user through an attribute called "user_id". But if the attribute is "owner_id" on a Group, that's fine, you can do:
82
+
83
+ ```ruby
84
+ @cohorts = CohortMe.analyze(period: "months",
85
+ activation_class: Group,
86
+ activation_user_id: 'owner_id',
87
+ activity_class: Message)
88
+ ```
89
+
90
+ Here's an example from Draft. It's slightly more complicated because I have guest users, and documents that can be blank from people kicking the tires. I don't want to count those. My cohort analysis looks like this:
91
+
92
+ ```ruby
93
+ non_guests = User.where("encrypted_password IS NOT NULL AND encrypted_password != ''").all
94
+ @period = "weeks"
95
+ activation_conditions = ["(content IS NOT NULL && content != '') and user_id IN (?)", non_guests]
96
+
97
+ @cohorts = CohortMe.analyze(period: @period,
98
+ activation_class: Document,
99
+ activation_conditions: activation_conditions)
100
+ ```
101
+
102
+ Data Returned
103
+ -------------
104
+ The data returned looks like this:
105
+
106
+ ```ruby
107
+ {cohort date1 => {
108
+ :count=>[integer, smaller integer, smaller integer],
109
+ :data=>[user event record, user event record]
110
+ }
111
+ ```
112
+
113
+ Installation
114
+ ------------
115
+
116
+ - Add `gem 'cohort_me'` to your Gemfile.
117
+ - Run `bundle install`.
118
+ - Restart your server
119
+ - Get your cohorts in a controller action. For example:
120
+
121
+ ```ruby
122
+ class Users
123
+ def performance
124
+ @cohorts = CohortMe.analyze(period: "weeks",
125
+ activation_class: Document)
126
+ render action: 'performance'
127
+ end
128
+ end
129
+ ```
130
+
131
+ - Do something with @cohorts in a view.
132
+ [Here's code you can use for your view](https://raw.github.com/n8/cohort_me/master/lib/cohort_me/_cohort_table.html.erb). It displays a basic cohort analysis table you can play with.
133
+ - If you look closely at that table image, you'll notice that the numbers are links. I've tweaked the table in my own app to be able to show me who exactly are those users returning to Draft. You can do the same:
134
+
135
+ ```erb
136
+ <%= link_to "#{((row[1][:count][i].to_f/start.to_f) * 100.00).round(0)}%", show_users_retention_path(cohort: row[0], period: i) %>
137
+ ```
138
+
139
+ And I have a Controller action that looks like this:
140
+
141
+ ```ruby
142
+ class RetentionController < ApplicationController
143
+
144
+ def show_users
145
+ @cohorts = CohortMe.analyze(activation_class: Document)
146
+
147
+ @documents = @cohorts[Date.parse(params[:cohort])][:data].select{|d| d.periods_out.to_i == params[:period].to_i}
148
+
149
+ user_ids = @documents.collect{|d| d.user_id }
150
+ @users = User.where("id IN (?)", user_ids)
151
+
152
+ end
153
+ end
154
+ ```
155
+
156
+ Feedback
157
+ --------
158
+ [Source code available on Github](https://github.com/n8/cohort_me). Feedback and pull requests are greatly appreciated.
26
159
 
27
- ## Contributing
28
160
 
29
- 1. Fork it
30
- 2. Create your feature branch (`git checkout -b my-new-feature`)
31
- 3. Commit your changes (`git commit -am 'Added some feature'`)
32
- 4. Push to the branch (`git push origin my-new-feature`)
33
- 5. Create new Pull Request
@@ -1,3 +1,3 @@
1
1
  module CohortMe
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/cohort_me.rb CHANGED
@@ -24,11 +24,9 @@ module CohortMe
24
24
  elsif interval_name == "days"
25
25
  start_from = 12.days.ago
26
26
  time_conversion = 86400
27
- cohort_label = "%Y-%j"
28
27
  elsif interval_name == "months"
29
28
  start_from = 12.months.ago
30
29
  time_conversion = 1.month.seconds
31
- cohort_label = "%Y-%b"
32
30
  end
33
31
 
34
32
  cohort_query = activation_class.select("#{activation_table_name}.#{activation_user_id}, MIN(#{activation_table_name}.created_at) as cohort_date").group("#{activation_user_id}").where("created_at > ?", start_from)
@@ -48,7 +46,7 @@ module CohortMe
48
46
 
49
47
  data = activity_class.where("created_at > ?", start_from).select(select_sql).joins("JOIN (" + cohort_query.to_sql + ") AS cohorts ON #{activity_table_name}.#{activity_user_id} = cohorts.#{activation_user_id}")
50
48
 
51
- unique_data = data.all.uniq{|d| [d.user_id, d.cohort_date, d.periods_out] }
49
+ unique_data = data.all.uniq{|d| [d.send(activity_user_id), d.cohort_date, d.periods_out] }
52
50
 
53
51
  analysis = unique_data.group_by{|d| convert_to_cohort_date(Time.parse(d.cohort_date.to_s), interval_name)}
54
52
  cohort_hash = Hash[analysis.sort_by { |cohort, data| cohort }]
@@ -72,9 +70,8 @@ module CohortMe
72
70
 
73
71
  def self.convert_to_cohort_date(datetime, interval)
74
72
  if interval == "weeks"
75
- year_and_week = datetime.strftime("%Y-%U").split("-")
76
- return Date.commercial(year_and_week[0].to_i, year_and_week[1].to_i + 1)
77
-
73
+ return datetime.at_beginning_of_week.to_date
74
+
78
75
  elsif interval == "days"
79
76
  return Date.parse(datetime.strftime("%Y-%m-%d"))
80
77
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cohort_me
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: