|
1 | | -schema_version: "1.0.0" |
2 | | -schema_date: "2025-01-20" |
3 | | -description: "CCHS missing data patterns and transformation rules - machine-actionable metadata reference" |
| 1 | +schema_version: "1.1.0" |
| 2 | +schema_date: "2026-07-15" |
| 3 | +description: "CCHS missing data patterns and priority rules - machine-actionable metadata" |
4 | 4 |
|
5 | 5 | # All codes and ranges in this schema are in the SOURCE coding domain (raw |
6 | | -# StatCan codes), not the harmonized/derived domain. Consumers: the |
7 | | -# clean_variables() fallback pattern and load_priority_rules() read the |
8 | | -# normative blocks (pattern_definitions, na_category_definitions); |
9 | | -# variable_assignments is reference documentation only - the per-variable |
10 | | -# source of truth is variable_details.csv. |
| 6 | +# StatCan codes), not the harmonized/derived domain. |
11 | 7 | applies_to: "source_codes" |
12 | 8 |
|
13 | | -# Cross-reference with human-readable documentation |
| 9 | +# Consumers (code that reads this file). The per-variable source of truth is |
| 10 | +# variable_details.csv; this schema supplies the pattern families, the |
| 11 | +# priority hierarchy, and the fallback pattern. |
| 12 | +consumers: |
| 13 | + - "load_cchs_missing_data() in R/load-schema.R" |
| 14 | + - ".default_cchs_pattern() in R/clean-variables.R" |
| 15 | + - "load_priority_rules() in R/missing-data-functions.R" |
| 16 | + |
14 | 17 | related_documentation: |
15 | 18 | user_guide: "vignettes/missing_value_conventions.qmd" |
16 | | - implementation_guide: "vignettes/missing_value_conventions.qmd" |
17 | | - |
| 19 | + |
18 | 20 | # ============================================================================ |
19 | | -# MISSING DATA PATTERN DEFINITIONS |
| 21 | +# MISSING DATA PATTERN DEFINITIONS (normative) |
20 | 22 | # ============================================================================ |
| 23 | +# Each family's priority_hierarchy is the single normative encoding of which |
| 24 | +# source codes map to which tagged-NA category. Tag values are symbolic |
| 25 | +# ("a", "b"); consumers construct haven::tagged_na() from them - this file |
| 26 | +# contains data, never executable code. |
21 | 27 | pattern_definitions: |
22 | 28 | title: "CCHS Missing Data Code Patterns" |
23 | | - description: "Authoritative specification of missing data patterns for cchsflow implementation" |
24 | | - version: "1.0.0" |
25 | | - |
26 | | - # Core pattern specifications |
| 29 | + description: "Missing-code families follow StatCan field width: single digit (valid 1-5), double digit (valid 1-95), triple digit (continuous)." |
| 30 | + |
27 | 31 | patterns: |
28 | 32 | single_digit_missing: |
29 | 33 | description: "Binary/ternary variables with valid responses 1-5" |
30 | 34 | valid_response_range: [1, 5] |
31 | | - missing_codes: [6, 7, 8, 9] |
32 | | - transformation_map: |
33 | | - 6: "haven::tagged_na('a')" # Not applicable |
34 | | - 7: "haven::tagged_na('b')" # Don't know |
35 | | - 8: "haven::tagged_na('b')" # Refusal |
36 | | - 9: "haven::tagged_na('b')" # Not stated |
37 | 35 | priority_hierarchy: |
38 | | - description: "Two-tier priority system: not_applicable wins over any missing_data" |
39 | | - not_applicable: |
| 36 | + description: "Two-tier priority: not_applicable wins over missing_data" |
| 37 | + not_applicable: |
40 | 38 | label: "Not applicable" |
41 | 39 | description: "Participant doesn't qualify for this question" |
42 | 40 | original_codes: [6] |
43 | 41 | tagged_na: ["a"] |
44 | 42 | missing_data: |
45 | 43 | label: "Missing data" |
46 | | - description: "All missing response types (don't know, refusal, not stated)" |
| 44 | + description: "Don't know (7), refusal (8), not stated (9)" |
47 | 45 | original_codes: [7, 8, 9] |
48 | 46 | tagged_na: ["b"] |
49 | | - |
| 47 | + |
50 | 48 | double_digit_missing: |
51 | 49 | description: "Multi-category scales with valid responses 1-95" |
52 | 50 | valid_response_range: [1, 95] |
53 | | - missing_codes: [96, 97, 98, 99] |
54 | | - critical_usage_note: "Required when max valid response > 5 (e.g., smoking status 6=never smoked)" |
55 | | - transformation_map: |
56 | | - 96: "haven::tagged_na('a')" # Not applicable |
57 | | - 97: "haven::tagged_na('b')" # Don't know |
58 | | - 98: "haven::tagged_na('b')" # Refusal |
59 | | - 99: "haven::tagged_na('b')" # Not stated |
| 51 | + critical_usage_note: "Required when max valid response > 5 (e.g., 6-category smoking status where 6 = never smoked is VALID)" |
60 | 52 | priority_hierarchy: |
61 | | - description: "Two-tier priority system: not_applicable wins over any missing_data" |
| 53 | + description: "Two-tier priority: not_applicable wins over missing_data" |
62 | 54 | not_applicable: |
63 | 55 | label: "Not applicable" |
64 | 56 | description: "Participant doesn't qualify for this question" |
65 | 57 | original_codes: [96] |
66 | 58 | tagged_na: ["a"] |
67 | 59 | missing_data: |
68 | 60 | label: "Missing data" |
69 | | - description: "All missing response types (don't know, refusal, not stated)" |
| 61 | + description: "Don't know (97), refusal (98), not stated (99)" |
70 | 62 | original_codes: [97, 98, 99] |
71 | 63 | tagged_na: ["b"] |
72 | | - |
| 64 | + |
73 | 65 | triple_digit_missing: |
74 | 66 | description: "Continuous measurements with variable-specific valid ranges" |
75 | 67 | valid_response_range: "variable_specific" |
76 | | - missing_codes: [996, 997, 998, 999] |
77 | | - decimal_variations: [999.6, 999.7, 999.8, 999.9] # Early cycles |
78 | | - transformation_map: |
79 | | - 996: "haven::tagged_na('a')" # Not applicable |
80 | | - 997: "haven::tagged_na('b')" # Don't know |
81 | | - 998: "haven::tagged_na('b')" # Refusal |
82 | | - 999: "haven::tagged_na('b')" # Not stated |
83 | | - 999.6: "haven::tagged_na('a')" # Not applicable (decimal) |
84 | | - 999.7: "haven::tagged_na('b')" # Don't know (decimal) |
85 | | - 999.8: "haven::tagged_na('b')" # Refusal (decimal) |
86 | | - 999.9: "haven::tagged_na('b')" # Not stated (decimal) |
87 | 68 | priority_hierarchy: |
88 | | - description: "Two-tier priority system: not_applicable wins over any missing_data" |
| 69 | + description: "Two-tier priority: not_applicable wins over missing_data" |
89 | 70 | not_applicable: |
90 | 71 | label: "Not applicable" |
91 | 72 | description: "Participant doesn't qualify for this question" |
92 | 73 | original_codes: [996] |
93 | 74 | tagged_na: ["a"] |
94 | | - decimal_codes: [999.6] |
| 75 | + decimal_codes: [999.6] # early-cycle variant |
95 | 76 | missing_data: |
96 | 77 | label: "Missing data" |
97 | | - description: "All missing response types (don't know, refusal, not stated)" |
| 78 | + description: "Don't know (997), refusal (998), not stated (999)" |
98 | 79 | original_codes: [997, 998, 999] |
99 | 80 | tagged_na: ["b"] |
100 | | - decimal_codes: [999.7, 999.8, 999.9] |
101 | | - |
102 | | -# ============================================================================ |
103 | | -# VARIABLE PATTERN ASSIGNMENTS |
104 | | -# ============================================================================ |
105 | | -variable_assignments: |
106 | | - title: "CCHS Variable Pattern Assignments" |
107 | | - description: "Machine-actionable assignments of missing data patterns to specific CCHS variables" |
108 | | - reference_guide: "vignettes/missing_value_conventions.qmd#pattern-selection-guidelines" |
109 | | - |
110 | | - smoking_variables: |
111 | | - SMK_005: |
112 | | - pattern: "single_digit_missing" |
113 | | - valid_range: [1, 3] |
114 | | - description: "Type of smoker presently" |
115 | | - SMK_030: |
116 | | - pattern: "single_digit_missing" |
117 | | - valid_range: [1, 2] |
118 | | - description: "Ever smoked daily" |
119 | | - SMK_01A: |
120 | | - pattern: "single_digit_missing" |
121 | | - valid_range: [1, 2] |
122 | | - description: "Smoked 100+ cigarettes in lifetime" |
123 | | - SMOKING_STATUS_DERIVED: |
124 | | - pattern: "double_digit_missing" # CRITICAL: 6 is valid (never smoked) |
125 | | - valid_range: [1, 6] |
126 | | - description: "Derived smoking status (6-category)" |
127 | | - critical_note: "Category 6 (never smoked) is VALID, not missing" |
128 | | - SMKG203: |
129 | | - pattern: "double_digit_missing" |
130 | | - valid_range: [1, 11] |
131 | | - description: "Age started smoking daily (categorical)" |
132 | | - SMKG207: |
133 | | - pattern: "double_digit_missing" |
134 | | - valid_range: [1, 11] |
135 | | - description: "Age started smoking daily (former daily smokers)" |
136 | | - SMK_204: |
137 | | - pattern: "triple_digit_missing" |
138 | | - valid_range: [0, 150] |
139 | | - description: "Cigarettes per day (daily smokers)" |
140 | | - SMK_208: |
141 | | - pattern: "triple_digit_missing" |
142 | | - valid_range: [0, 150] |
143 | | - description: "Cigarettes per day (former daily smokers)" |
144 | | - |
145 | | - anthropometric_variables: |
146 | | - HWTDGHTM: |
147 | | - pattern: "triple_digit_missing" |
148 | | - valid_range: [0.5, 2.5] |
149 | | - description: "Height in meters" |
150 | | - HWTDGWTK: |
151 | | - pattern: "triple_digit_missing" |
152 | | - valid_range: [20, 300] |
153 | | - description: "Weight in kilograms" |
| 81 | + decimal_codes: [999.7, 999.8, 999.9] # early-cycle variants |
154 | 82 |
|
155 | 83 | # ============================================================================ |
156 | | -# TRANSFORMATION RULES |
| 84 | +# NA CATEGORY SEMANTICS |
157 | 85 | # ============================================================================ |
158 | | -transformation_rules: |
159 | | - title: "CCHS Missing Data Transformation Implementation" |
160 | | - description: "Machine-actionable rules for converting original CCHS codes to standardized NA categories" |
161 | | - reference_documentation: "vignettes/missing_value_conventions.qmd#current-classification-used-in-cchsflow" |
162 | | - |
163 | | - na_category_definitions: |
164 | | - "NA::a": |
165 | | - semantic_meaning: "Not applicable" |
166 | | - original_codes: [6, 96, 996] |
167 | | - statistical_treatment: "Exclude from denominators and percentage calculations" |
168 | | - |
169 | | - "NA::b": |
170 | | - semantic_meaning: "Missing data" |
171 | | - original_codes: [7, 8, 9, 97, 98, 99, 997, 998, 999] |
172 | | - statistical_treatment: "Include in denominators, exclude from numerators" |
173 | | - |
174 | | - implementation: |
175 | | - primary_function: "preprocess_cchs_missing_codes" |
176 | | - pattern_aliases: |
177 | | - # Deprecated names for backward compatibility |
178 | | - standard_response: "single_digit_missing" |
179 | | - categorical_age: "double_digit_missing" |
180 | | - continuous_standard: "triple_digit_missing" |
181 | | - |
182 | | - pattern_selection_rules: |
183 | | - reference: "vignettes/missing_value_conventions.qmd#pattern-selection-guidelines" |
184 | | - decision_logic: |
185 | | - continuous_variables: "triple_digit_missing" |
186 | | - max_valid_over_5: "double_digit_missing" |
187 | | - max_valid_under_6: "single_digit_missing" |
| 86 | +# Epidemiological meaning and analysis guidance per tagged-NA category. |
| 87 | +# Codes are NOT repeated here - they live in the family definitions above. |
| 88 | +na_category_semantics: |
| 89 | + "NA::a": |
| 90 | + semantic_meaning: "Not applicable" |
| 91 | + statistical_treatment: "Exclude from denominators and percentage calculations" |
| 92 | + "NA::b": |
| 93 | + semantic_meaning: "Missing data" |
| 94 | + statistical_treatment: "Include in denominators, exclude from numerators" |
188 | 95 |
|
189 | 96 | # ============================================================================ |
190 | | -# IMPLEMENTATION REFERENCE |
| 97 | +# AUTHORING GUIDANCE (non-normative) |
191 | 98 | # ============================================================================ |
192 | | -implementation: |
193 | | - primary_function: "preprocess_cchs_missing_codes" |
194 | | - pattern_names: ["single_digit_missing", "double_digit_missing", "triple_digit_missing"] |
195 | | - constants_file: "R/validation-constants.R" |
196 | | - |
197 | | - testing_requirements: |
198 | | - boundary_testing: "Test all valid category endpoints and missing codes" |
199 | | - type_safety: "Validate haven::tagged_na() preservation" |
200 | | - integration: "Verify rec_with_table() workflow compatibility" |
201 | | - |
| 99 | +# How to choose a family when adding a variable to the worksheets. Judgment |
| 100 | +# guidance for authors, not machine-executed logic. |
| 101 | +authoring_guidance: |
| 102 | + family_selection: |
| 103 | + continuous_variables: "triple_digit_missing" |
| 104 | + max_valid_over_5: "double_digit_missing (single-digit codes would collide with valid categories)" |
| 105 | + max_valid_under_6: "single_digit_missing" |
| 106 | + canonical_examples: |
| 107 | + single_digit_missing: "SMK_005 (type of smoker, valid 1-3), ADL_01 (needs help, valid 1-2)" |
| 108 | + double_digit_missing: "SMKDSTY 6-category smoking status - category 6 (never smoked) is VALID, not missing; SMKG203 (age started, valid 1-11)" |
| 109 | + triple_digit_missing: "SMK_204 (cigarettes per day), HWTGHTM (height in metres)" |
202 | 110 | cycle_considerations: |
203 | | - stable_patterns: "Core missing codes (6,7,8,9) consistent since CCHS 2001" |
204 | | - decimal_variations: "Early cycles use 999.6, later cycles use whole numbers" |
205 | | - handled_automatically: "cchsflow normalizes all variations" |
| 111 | + stable_patterns: "Core missing codes (6,7,8,9 families) consistent since CCHS 2001" |
| 112 | + decimal_variations: "Early cycles use 999.6-999.9 for some continuous variables; declared in triple_digit_missing and handled by the fallback pattern" |
206 | 113 |
|
207 | 114 | # ============================================================================ |
208 | 115 | # METADATA AND VERSIONING |
209 | 116 | # ============================================================================ |
210 | 117 | metadata: |
211 | 118 | schema_authority: "cchsflow development team" |
212 | 119 | last_reviewed: "2026-07-15" |
213 | | - next_review_due: "2025-07-20" |
| 120 | + next_review_due: "2027-01-15" |
214 | 121 | version_history: |
| 122 | + "1.1.0": "Slimmed to one normative encoding per fact: removed transformation_map (R-code strings; redundant with priority_hierarchy), removed per-variable assignments (variable_details.csv is the per-variable source of truth; judgment preserved in authoring_guidance), removed stale implementation pointers (referenced never-merged functions), replaced with an accurate consumers list. Added applies_to: source_codes." |
215 | 123 | "1.0.0": "Initial comprehensive specification with standardized pattern names (single/double/triple_digit_missing)" |
216 | | - |
217 | | - related_documents: |
218 | | - primary_reference: "vignettes/missing_value_conventions.qmd" |
219 | | - implementation_guide: "vignettes/missing_value_conventions.qmd" |
220 | | - constants_file: "R/validation-constants.R" |
221 | | - helper_functions: "R/missing-data-functions.R" |
222 | | - |
223 | 124 | contact_information: |
224 | 125 | maintainer: "cchsflow development team" |
225 | 126 | issues: "https://github.com/Big-Life-Lab/cchsflow/issues" |
|
0 commit comments