Class: Crosstab::Cell

Inherits:
Object
  • Object
show all
Defined in:
lib/crosstab/cell.rb

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Cell

Optionally, can take options :base and :frequency for a fast initialization.

Example:

cell = Crosstab::Cell.new
cell.frequency 2
cell.base 4
cell.percentage
# => 0.5

cell = Crosstab::Cell.new :base => 4, :frequency => 2
cell.percentage
# => 0.5


16
17
18
19
# File 'lib/crosstab/cell.rb', line 16

def initialize(options={})
  base options[:base] if options[:base]
  frequency options[:frequency] if options[:frequency]    
end

Instance Method Details

#base(value = nil) ⇒ Object

DSL accessor for the base attribute. The base is the number of records used in calculations for this cell.

Example:

cell = Crosstab::Cell.new

cell.frequency 2
cell.base 4

cell.percentage
# => 0.5


33
34
35
36
37
38
39
# File 'lib/crosstab/cell.rb', line 33

def base(value=nil)
  if value
    @base = value
  else
    @base ||= 0
  end
end

#column(value = nil) ⇒ Object

DSL accessor for the column that this cell belongs to.

Example:

cell = Crosstab::Cell.new
cell.column
#=> nil

cell.column Crosstab::Column.new("Male", :a => 1)

column
#=> Crosstab::Column

column.title
#=> "Male"


155
156
157
158
159
160
161
# File 'lib/crosstab/cell.rb', line 155

def column(value=nil)
  if value
    @column = value
  else
    @column ||= nil
  end
end

#frequency(value = nil) ⇒ Object

Returns and sets the frequency for this cell, that is, the number of records that meet both the row and column qualifications.

Example:

cell = Crosstab::Cell.new

cell.frequency 2
cell.base 4

cell.percentage
# => 0.5


53
54
55
56
57
58
59
# File 'lib/crosstab/cell.rb', line 53

def frequency(value=nil)
  if value
    @frequency = value
  else
    @frequency ||= 0
  end
end

#percentageObject

Returns the frequency divided by the base. Always a float.

Example:

cell = Crosstab::Cell.new

cell.frequency 2
cell.base 4

cell.percentage
# => 0.5


73
74
75
76
77
78
79
# File 'lib/crosstab/cell.rb', line 73

def percentage
  if base > 0
    frequency.to_f / base.to_f
  else
    0.0
  end
end

#resultObject

Returns an array of default stats (frequency, percentage, then sigtesting). It’s only really useful for printing within reports. If the frequency of the cell is 0, it returns [ “–” ] because what’s the point of displaying 0, 0%?

Example:

cell = Crosstab::Cell.new

cell.frequency 2
cell.base 4

cell.result
# => [2, 0.5]


95
96
97
98
99
100
101
# File 'lib/crosstab/cell.rb', line 95

def result
  if frequency > 0
    [frequency, "#{(percentage * 100).round}%" ]
  else
    ["--"]
  end
end

#significant_against?(test_cell, level = 0.95) ⇒ Boolean

Tests this cell against another and returns true if it is statistically significant. The default testing level is 95%, represented as a float (i.e., 0.95.) Other levels supported are 0.85, 0.90, and 0.98.

Example:

cell1 = Crosstab::Cell.new :base => 100, :frequency => 65
cell2 = Crosstab::Cell.new :base => 100, :frequency => 50

cell1.significant_against? cell2
# => true

Returns:

  • (Boolean)


114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/crosstab/cell.rb', line 114

def significant_against?(test_cell, level=0.95)
  zfactor = { 0.98 => 2.327,
              0.95 => 1.960,
              0.90 => 1.645,
              0.85 => 1.440 }

  # From what I understand, a z-test is meaningless if either of the two cells are in the bottom or top 10%.
  # So we return false.  If you're any good at statistics, I would love to hear your opinion on this.  
  # I've done this shit for ten years and I'm still copying formulas out of books.  Frankly, it sounds odd,
  # and I can't seem to find any good documentation on why it is that we do it this way.  10% sounds like a fucking guess.

	return false unless [self, test_cell].all? { |x| (0.10..0.90).include? x.percentage }
	
	# The preperation
	a = self.percentage * self.base + test_cell.percentage * test_cell.base
	b = self.base + test_cell.base
	c = 1.0 / self.base + 1.0 / test_cell.base

  # The main calculation
  z = (self.percentage - test_cell.percentage) / Math.sqrt(a / b * (1 - a / b) * c)

  # The test
  z >= zfactor[level]
end