vr_12_score 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/vr_12_score.rb +147 -0
  3. metadata +59 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0e650a4cb7490c1fba739a0ce2ddd6602737f95f
4
+ data.tar.gz: 90281394a78b1766d0f706fba13118658593b3d4
5
+ SHA512:
6
+ metadata.gz: 568a46370d1fb631856c7eaa99c4f8bd192c35b22a6df12ee41321cc9018f0519e4f5fbdc1f0cd365a8d380614c379f62c421be82e13bf48372d22eb840e60a5
7
+ data.tar.gz: d853941687edb5bee03adbeb211d87a857ad3bc4c54f59e27f141ecd98d52f9fd570d92b722b3b9666948696cdbd63edf20788ce55118da69b4324fd51d00012
@@ -0,0 +1,147 @@
1
+ require 'csv'
2
+
3
+ # @author Kevin Spevak
4
+ class Vr12Score
5
+ QUESTION_LABELS = [:gh1, :pf02, :pf04, :vrp2, :vrp3, :vre2, :vre3, :bp2, :mh3, :vt2, :mh4, :sf2]
6
+
7
+ # @return [String] The directory of the csv files containing the weights used to score the vr-12 survey.
8
+ attr_accessor :weights_dir
9
+
10
+ # @return [String] The name of the file containing weights for calculating the physical component
11
+ # score for a vr-12 survey administered by phone. Defaults to "pcs_phone.csv"
12
+ attr_accessor :pcs_phone_file
13
+
14
+ # @return [String] The name of the file containing weights for calculating the mental component
15
+ # score for a vr-12 survey administered by phone. Defaults to "mcs_phone.csv"
16
+ attr_accessor :mcs_phone_file
17
+
18
+ # @return [String] The name of the file containing weights for calculating the physical component
19
+ # score for a mail-out vr-12 survey. Defaults to "pcs_mail.csv"
20
+ attr_accessor :pcs_mail_file
21
+
22
+ # @return [String] The name of the file containing weights for calculating the mental component
23
+ # score for a mail-out vr-12 survey. Defaults to "mcs_mail.csv"
24
+ attr_accessor :mcs_mail_file
25
+
26
+ # @param weights_dir [String] ("weights") The directory of the csv files containing the weights used
27
+ # to score the vr-12 survey.
28
+ def initialize(weights_dir="weights")
29
+ @weights_dir = weights_dir
30
+ @pcs_phone_file = "pcs_phone.csv"
31
+ @mcs_phone_file = "mcs_phone.csv"
32
+ @pcs_mail_file = "pcs_mail.csv"
33
+ @mcs_mail_file = "mcs_mail.csv"
34
+ end
35
+
36
+ # Calculates the score for a response to the vr-12 survey
37
+ # @param survey [Hash] The survey response data. This argument must contain 13 keys: One for each of
38
+ # the 12 questions in the vr-12 survey, and a :type key.
39
+ # @option survey [String] :type The method that was used to administer this survey. "phone" or "mail"
40
+ # @option survey [Number] :gh1 The response to question 1: General Health (1-5)
41
+ # @option survey [Number] :pf02 The response to question 2a: Physical Functioning part a (1-3)
42
+ # @option survey [Number] :pf04 The response to question 2b: Physical Functioning part b (1-3)
43
+ # @option survey [Number] :vrp2 The response to question 3a: Physical Work Limitations part a (1-5)
44
+ # @option survey [Number] :vrp3 The response to question 3b: Physical Work Limitations part b (1-5)
45
+ # @option survey [Number] :vre2 The response to question 4a: Emotional Work Limitations part a (1-5)
46
+ # @option survey [Number] :vre3 The response to question 4b: Emotional Work Limitations part b (1-5)
47
+ # @option survey [Number] :bp2 The response to question 5: Bodily Pain (1-5)
48
+ # @option survey [Number] :mh3 The response to question 6a: Mental Health - Peaceful (1-6)
49
+ # @option survey [Number] :vt2 The response to question 6b: Vitality - Energy (1-6)
50
+ # @option survey [Number] :mh4 The response to question 6c: Mental Health - Down (1-6)
51
+ # @option survey [Number] :sf2 The response to question 7: Social Functioning (1-5)
52
+ # @return [Hash{Symbol => Number}] The physical component score and mental component score.
53
+ def score(survey)
54
+ if !survey || !survey.is_a?(Hash)
55
+ raise ArgumentError.new("requires a hash of survey data")
56
+ end
57
+ if (QUESTION_LABELS - survey.keys).length > 0
58
+ raise ArgumentError.new("Survey data missing keys for questions #{QUESTION_LABELS - survey.keys}")
59
+ end
60
+ non_numeric_labels = QUESTION_LABELS.select {|q| !(survey[q].nil? || survey[q].is_a?(Numeric))}
61
+ if non_numeric_labels.length > 0
62
+ raise ArgumentError.new("Values for questions #{non_numeric_labels} must be numeric or nil.")
63
+ end
64
+ if survey[:type] == "phone"
65
+ pcs_data = pcs_phone_data
66
+ mcs_data = mcs_phone_data
67
+ elsif survey[:type] == "mail"
68
+ pcs_data = pcs_mail_data
69
+ mcs_data = mcs_mail_data
70
+ else
71
+ raise ArgumentError.new('Survey data must include a type that is either "phone" or "mail"')
72
+ end
73
+
74
+ # Convert answers to 0-100 scale values
75
+ survey[:gh1] = case survey[:gh1]
76
+ when nil then nil
77
+ when 1 then 100
78
+ when 2 then 85
79
+ when 3 then 60
80
+ when 4 then 35
81
+ when 5 then 0
82
+ else raise ArgumentError.new("Value for :gh1 must be an integer from 1 to 5")
83
+ end
84
+ blank_questions = QUESTION_LABELS.select {|q| survey[q].nil?}
85
+ ([:pf02, :pf04] - blank_questions).each do |q|
86
+ raise ArgumentError.new("Value for #{q} must be an integer from 1 to 3") unless [1, 2, 3].include? survey[q]
87
+ survey[q] = (survey[q] - 1) * 50
88
+ end
89
+ ([:vrp2, :vrp3, :vre2, :vre3, :bp2, :sf2] - blank_questions).each do |q|
90
+ raise ArgumentError.new("Value for #{q} must be an integer from 1 to 5") unless (1..5).to_a.include? survey[q]
91
+ survey[q] = (5 - survey[q]) * 25
92
+ end
93
+ survey[:sf2] = 100 - survey[:sf2] if survey[:sf2]
94
+ ([:mh3, :vt2, :mh4] - blank_questions).each do |q|
95
+ raise ArgumentError.new("Value for #{q} must be an integer from 1 to 6") unless (1..6).to_a.include? survey[q]
96
+ survey[q] = (6 - survey[q]) * 20
97
+ end
98
+ survey[:mh4] = 100 - survey[:mh4] if survey[:mh4]
99
+
100
+ # Find key to look up question weights based on blank questions
101
+ key = 0
102
+ blank_questions.each {|q| key |= 1 << QUESTION_LABELS.reverse.index(q)}
103
+
104
+ pcs_row = pcs_data[:key].index(key)
105
+ mcs_row = mcs_data[:key].index(key)
106
+
107
+ pcs = mcs = nil
108
+ if pcs_row
109
+ pcs_weights = pcs_data[pcs_row]
110
+ # Calculate score by taking the weighted sum of the question responses given the appropriate weights,
111
+ # then adding the appropriate constant term, based on which questions were answered.
112
+ # Convert survey answers to integers to handle nil values (will not affect the weighted sum)
113
+ # Add 'x' to end of question labels to look up weights to match the headers of the weight files.
114
+ pcs = QUESTION_LABELS.map {|q| survey[q].to_i * pcs_weights[weight_name(q)]}.reduce(&:+) + pcs_weights[:cons]
115
+ end
116
+
117
+ if mcs_row
118
+ mcs_weights = mcs_data[mcs_row]
119
+ mcs = QUESTION_LABELS.map {|q| survey[q].to_i * mcs_weights[weight_name(q)]}.reduce(&:+) + mcs_weights[:cons]
120
+ end
121
+
122
+ return {pcs: pcs, mcs: mcs}
123
+ end
124
+
125
+ private
126
+
127
+ # Convert question label to name of corresponding column in weights file
128
+ def weight_name(question_label)
129
+ (question_label.to_s.sub(/^vr/, "r") + "x").to_sym
130
+ end
131
+
132
+ def pcs_phone_data
133
+ @pcs_phone_data ||= CSV.table(File.join(@weights_dir, @pcs_phone_file))
134
+ end
135
+
136
+ def mcs_phone_data
137
+ @mcs_phone_data ||= CSV.table(File.join(@weights_dir, @mcs_phone_file))
138
+ end
139
+
140
+ def pcs_mail_data
141
+ @pcs_mail_data ||= CSV.table(File.join(@weights_dir, @pcs_mail_file))
142
+ end
143
+
144
+ def mcs_mail_data
145
+ @mcs_mail_data ||= CSV.table(File.join(@weights_dir, @mcs_mail_file))
146
+ end
147
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vr_12_score
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Trainer Rx
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-05-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.4'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.4'
27
+ description: A utility for calculating the VR-12 Physical Component Score (PCS) and
28
+ Mental Component Score (MCS)
29
+ email: dev.support@trainer-rx.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/vr_12_score.rb
35
+ homepage: https://github.com/trainer-rx/vr_12_score
36
+ licenses:
37
+ - MIT
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 2.2.2
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: VR-12 scoring tool
59
+ test_files: []