Class: Vr12Score

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

Overview

Author:

  • Kevin Spevak

Constant Summary collapse

QUESTION_LABELS =
[:gh1, :pf02, :pf04, :vrp2, :vrp3, :vre2, :vre3, :bp2, :mh3, :vt2, :mh4, :sf2]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(weights_dir = "weights") ⇒ Vr12Score

Returns a new instance of Vr12Score.

Parameters:

  • weights_dir (String) (defaults to: "weights")

    (“weights”) The directory of the csv files containing the weights used to score the vr-12 survey.



28
29
30
31
32
33
34
# File 'lib/vr_12_score.rb', line 28

def initialize(weights_dir="weights")
  @weights_dir    = weights_dir
  @pcs_phone_file = "pcs_phone.csv"
  @mcs_phone_file = "mcs_phone.csv"
  @pcs_mail_file  = "pcs_mail.csv"
  @mcs_mail_file  = "mcs_mail.csv"
end

Instance Attribute Details

#mcs_mail_fileString

Returns The name of the file containing weights for calculating the mental component score for a mail-out vr-12 survey. Defaults to “mcs_mail.csv”.

Returns:

  • (String)

    The name of the file containing weights for calculating the mental component score for a mail-out vr-12 survey. Defaults to “mcs_mail.csv”



24
25
26
# File 'lib/vr_12_score.rb', line 24

def mcs_mail_file
  @mcs_mail_file
end

#mcs_phone_fileString

Returns The name of the file containing weights for calculating the mental component score for a vr-12 survey administered by phone. Defaults to “mcs_phone.csv”.

Returns:

  • (String)

    The name of the file containing weights for calculating the mental component score for a vr-12 survey administered by phone. Defaults to “mcs_phone.csv”



16
17
18
# File 'lib/vr_12_score.rb', line 16

def mcs_phone_file
  @mcs_phone_file
end

#pcs_mail_fileString

Returns The name of the file containing weights for calculating the physical component score for a mail-out vr-12 survey. Defaults to “pcs_mail.csv”.

Returns:

  • (String)

    The name of the file containing weights for calculating the physical component score for a mail-out vr-12 survey. Defaults to “pcs_mail.csv”



20
21
22
# File 'lib/vr_12_score.rb', line 20

def pcs_mail_file
  @pcs_mail_file
end

#pcs_phone_fileString

Returns The name of the file containing weights for calculating the physical component score for a vr-12 survey administered by phone. Defaults to “pcs_phone.csv”.

Returns:

  • (String)

    The name of the file containing weights for calculating the physical component score for a vr-12 survey administered by phone. Defaults to “pcs_phone.csv”



12
13
14
# File 'lib/vr_12_score.rb', line 12

def pcs_phone_file
  @pcs_phone_file
end

#weights_dirString

Returns The directory of the csv files containing the weights used to score the vr-12 survey.

Returns:

  • (String)

    The directory of the csv files containing the weights used to score the vr-12 survey.



8
9
10
# File 'lib/vr_12_score.rb', line 8

def weights_dir
  @weights_dir
end

Instance Method Details

#score(survey) ⇒ Hash{Symbol => Number}

Calculates the score for a response to the vr-12 survey

Parameters:

  • survey (Hash)

    The survey response data. This argument must contain 13 keys: One for each of the 12 questions in the vr-12 survey, and a :type key.

Options Hash (survey):

  • :type (String)

    The method that was used to administer this survey. “phone” or “mail”

  • :gh1 (Number)

    The response to question 1: General Health (1-5)

  • :pf02 (Number)

    The response to question 2a: Physical Functioning part a (1-3)

  • :pf04 (Number)

    The response to question 2b: Physical Functioning part b (1-3)

  • :vrp2 (Number)

    The response to question 3a: Physical Work Limitations part a (1-5)

  • :vrp3 (Number)

    The response to question 3b: Physical Work Limitations part b (1-5)

  • :vre2 (Number)

    The response to question 4a: Emotional Work Limitations part a (1-5)

  • :vre3 (Number)

    The response to question 4b: Emotional Work Limitations part b (1-5)

  • :bp2 (Number)

    The response to question 5: Bodily Pain (1-5)

  • :mh3 (Number)

    The response to question 6a: Mental Health - Peaceful (1-6)

  • :vt2 (Number)

    The response to question 6b: Vitality - Energy (1-6)

  • :mh4 (Number)

    The response to question 6c: Mental Health - Down (1-6)

  • :sf2 (Number)

    The response to question 7: Social Functioning (1-5)

Returns:

  • (Hash{Symbol => Number})

    The physical component score and mental component score.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/vr_12_score.rb', line 53

def score(survey)
  if !survey || !survey.is_a?(Hash)
    raise ArgumentError.new("requires a hash of survey data")
  end
  if (QUESTION_LABELS - survey.keys).length > 0
    raise ArgumentError.new("Survey data missing keys for questions #{QUESTION_LABELS - survey.keys}")
  end
  non_numeric_labels = QUESTION_LABELS.select {|q| !(survey[q].nil? || survey[q].is_a?(Numeric))}
  if non_numeric_labels.length > 0
    raise ArgumentError.new("Values for questions #{non_numeric_labels} must be numeric or nil.")
  end
  if survey[:type] == "phone"
    pcs_data = pcs_phone_data
    mcs_data = mcs_phone_data
  elsif survey[:type] == "mail"
    pcs_data = pcs_mail_data
    mcs_data = mcs_mail_data
  else
    raise ArgumentError.new('Survey data must include a type that is either "phone" or "mail"')
  end

  # Convert answers to 0-100 scale values
  survey[:gh1] = case survey[:gh1]
                 when nil then nil
                 when 1 then 100
                 when 2 then 85
                 when 3 then 60
                 when 4 then 35
                 when 5 then 0
                 else raise ArgumentError.new("Value for :gh1 must be an integer from 1 to 5")
  end
  blank_questions = QUESTION_LABELS.select {|q| survey[q].nil?}
  ([:pf02, :pf04] - blank_questions).each do |q|
    raise ArgumentError.new("Value for #{q} must be an integer from 1 to 3") unless [1, 2, 3].include? survey[q]
    survey[q] = (survey[q] - 1) * 50
  end
  ([:vrp2, :vrp3, :vre2, :vre3, :bp2, :sf2] - blank_questions).each do |q|
    raise ArgumentError.new("Value for #{q} must be an integer from 1 to 5") unless (1..5).to_a.include? survey[q]
    survey[q] = (5 - survey[q]) * 25
  end
  survey[:sf2] = 100 - survey[:sf2] if survey[:sf2]
  ([:mh3, :vt2, :mh4] - blank_questions).each do |q|
    raise ArgumentError.new("Value for #{q} must be an integer from 1 to 6") unless (1..6).to_a.include? survey[q]
    survey[q] = (6 - survey[q]) * 20
  end
  survey[:mh4] = 100 - survey[:mh4] if survey[:mh4]

  # Find key to look up question weights based on blank questions
  key = 0
  blank_questions.each {|q| key |= 1 << QUESTION_LABELS.reverse.index(q)}

  pcs_row = pcs_data[:key].index("#{key}")
  mcs_row = mcs_data[:key].index("#{key}")

  pcs = mcs = nil
  if pcs_row
    pcs_weights = pcs_data[pcs_row]
    # Calculate score by taking the weighted sum of the question responses given the appropriate weights,
    # then adding the appropriate constant term, based on which questions were answered.
    # Convert survey answers to integers to handle nil values (will not affect the weighted sum)
    # Add 'x' to end of question labels to look up weights to match the headers of the weight files.
    pcs = QUESTION_LABELS.map {|q| survey[q].to_i * pcs_weights[weight_name(q)].to_f}.reduce(&:+) + pcs_weights[:cons].to_f
  end

  if mcs_row
    mcs_weights = mcs_data[mcs_row]
    mcs = QUESTION_LABELS.map {|q| survey[q].to_i * mcs_weights[weight_name(q)].to_f}.reduce(&:+) + mcs_weights[:cons].to_f
  end

  return {pcs: pcs, mcs: mcs}
end