Class: Split::Alternative

Inherits:
Object
  • Object
show all
Defined in:
lib/split/alternative.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, experiment_name) ⇒ Alternative

Returns a new instance of Alternative.



9
10
11
12
13
14
15
16
17
18
19
# File 'lib/split/alternative.rb', line 9

def initialize(name, experiment_name)
  @experiment_name = experiment_name
  if Hash === name
    @name = name.keys.first
    @weight = name.values.first
  else
    @name = name
    @weight = 1
  end
  @p_winner = 0.0
end

Instance Attribute Details

#experiment_nameObject

Returns the value of attribute experiment_name.



5
6
7
# File 'lib/split/alternative.rb', line 5

def experiment_name
  @experiment_name
end

#nameObject

Returns the value of attribute name.



4
5
6
# File 'lib/split/alternative.rb', line 4

def name
  @name
end

#recorded_infoObject

Returns the value of attribute recorded_info.



7
8
9
# File 'lib/split/alternative.rb', line 7

def recorded_info
  @recorded_info
end

#weightObject

Returns the value of attribute weight.



6
7
8
# File 'lib/split/alternative.rb', line 6

def weight
  @weight
end

Instance Method Details

#all_completed_countObject



52
53
54
55
56
57
58
59
60
# File 'lib/split/alternative.rb', line 52

def all_completed_count
  if goals.empty?
    completed_count
  else
    goals.inject(completed_count) do |sum, g|
      sum + completed_count(g)
    end
  end
end

#completed_count(goal = nil) ⇒ Object



47
48
49
50
# File 'lib/split/alternative.rb', line 47

def completed_count(goal = nil)
  field = set_field(goal)
  Split.redis.hget(key, field).to_i
end

#control?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/split/alternative.rb', line 92

def control?
  experiment.control.name == self.name
end

#conversion_rate(goal = nil) ⇒ Object



96
97
98
99
# File 'lib/split/alternative.rb', line 96

def conversion_rate(goal = nil)
  return 0 if participant_count.zero?
  (completed_count(goal).to_f)/participant_count.to_f
end

#deleteObject



177
178
179
# File 'lib/split/alternative.rb', line 177

def delete
  Split.redis.del(key)
end

#experimentObject



101
102
103
# File 'lib/split/alternative.rb', line 101

def experiment
  Split::ExperimentCatalog.find(experiment_name)
end

#extra_infoObject



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/split/alternative.rb', line 128

def extra_info
  data = Split.redis.hget(key, 'recorded_info')
  if data && data.length > 1
    begin
      JSON.parse(data)
    rescue
      {}
    end
  else
    {}
  end
end

#goalsObject



25
26
27
# File 'lib/split/alternative.rb', line 25

def goals
  self.experiment.goals
end

#increment_completion(goal = nil) ⇒ Object



87
88
89
90
# File 'lib/split/alternative.rb', line 87

def increment_completion(goal = nil)
  field = set_field(goal)
  Split.redis.hincrby(key, field, 1)
end

#increment_participationObject



83
84
85
# File 'lib/split/alternative.rb', line 83

def increment_participation
  Split.redis.hincrby key, 'participant_count', 1
end

#p_winner(goal = nil) ⇒ Object



29
30
31
32
# File 'lib/split/alternative.rb', line 29

def p_winner(goal = nil)
  field = set_prob_field(goal)
  @p_winner = Split.redis.hget(key, field).to_f
end

#participant_countObject



39
40
41
# File 'lib/split/alternative.rb', line 39

def participant_count
  Split.redis.hget(key, 'participant_count').to_i
end

#participant_count=(count) ⇒ Object



43
44
45
# File 'lib/split/alternative.rb', line 43

def participant_count=(count)
  Split.redis.hset(key, 'participant_count', count.to_i)
end

#record_extra_info(k, value = 1) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/split/alternative.rb', line 141

def record_extra_info(k, value = 1)
  @recorded_info = self.extra_info || {}

  if value.kind_of?(Numeric)
    @recorded_info[k] ||= 0
    @recorded_info[k] += value
  else
    @recorded_info[k] = value
  end

  Split.redis.hset key, 'recorded_info', (@recorded_info || {}).to_json
end

#resetObject



167
168
169
170
171
172
173
174
175
# File 'lib/split/alternative.rb', line 167

def reset
  Split.redis.hmset key, 'participant_count', 0, 'completed_count', 0, 'recorded_info', nil
  unless goals.empty?
    goals.each do |g|
      field = "completed_count:#{g}"
      Split.redis.hset key, field, 0
    end
  end
end

#saveObject



154
155
156
157
158
159
# File 'lib/split/alternative.rb', line 154

def save
  Split.redis.hsetnx key, 'participant_count', 0
  Split.redis.hsetnx key, 'completed_count', 0
  Split.redis.hsetnx key, 'p_winner', p_winner
  Split.redis.hsetnx key, 'recorded_info', (@recorded_info || {}).to_json
end

#set_completed_count(count, goal = nil) ⇒ Object



78
79
80
81
# File 'lib/split/alternative.rb', line 78

def set_completed_count(count, goal = nil)
  field = set_field(goal)
  Split.redis.hset(key, field, count.to_i)
end

#set_field(goal) ⇒ Object



66
67
68
69
70
# File 'lib/split/alternative.rb', line 66

def set_field(goal)
  field = "completed_count"
  field += ":" + goal unless goal.nil?
  return field
end

#set_p_winner(prob, goal = nil) ⇒ Object



34
35
36
37
# File 'lib/split/alternative.rb', line 34

def set_p_winner(prob, goal = nil)
  field = set_prob_field(goal)
  Split.redis.hset(key, field, prob.to_f)
end

#set_prob_field(goal) ⇒ Object



72
73
74
75
76
# File 'lib/split/alternative.rb', line 72

def set_prob_field(goal)
  field = "p_winner"
  field += ":" + goal unless goal.nil?
  return field
end

#to_sObject



21
22
23
# File 'lib/split/alternative.rb', line 21

def to_s
  name
end

#unfinished_countObject



62
63
64
# File 'lib/split/alternative.rb', line 62

def unfinished_count
  participant_count - all_completed_count
end

#validate!Object



161
162
163
164
165
# File 'lib/split/alternative.rb', line 161

def validate!
  unless String === @name || hash_with_correct_values?(@name)
    raise ArgumentError, 'Alternative must be a string'
  end
end

#z_score(goal = nil) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/split/alternative.rb', line 105

def z_score(goal = nil)
  # p_a = Pa = proportion of users who converted within the experiment split (conversion rate)
  # p_c = Pc = proportion of users who converted within the control split (conversion rate)
  # n_a = Na = the number of impressions within the experiment split
  # n_c = Nc = the number of impressions within the control split

  control = experiment.control
  alternative = self

  return 'N/A' if control.name == alternative.name

  p_a = alternative.conversion_rate(goal)
  p_c = control.conversion_rate(goal)

  n_a = alternative.participant_count
  n_c = control.participant_count

  # can't calculate zscore for P(x) > 1
  return 'N/A' if p_a > 1 || p_c > 1

  Split::Zscore.calculate(p_a, n_a, p_c, n_c)
end