Skip to content

Commit 544f4b8

Browse files
committed
Give rules as true/false rather than strings [#20]
- Rule columns prefixed with 'rules_' - Data columns prefixed with 'data_' - ID columns prefixed with 'id_' Also removed some superfluous calculations.
1 parent f949d7f commit 544f4b8

File tree

6 files changed

+505
-296
lines changed

6 files changed

+505
-296
lines changed

README.md

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -240,26 +240,31 @@ Each row in a Rule view tells you whether a Sample was within control limits, or
240240
Let's look at Table 6.2 and see if we can find out-of-control Samples:
241241

242242
```sql
243-
select sample_id,
244-
controlled_value,
245-
upper_limit,
246-
control_status
243+
select id_sample as "Sample ID",
244+
data_controlled_value as "Sample Average",
245+
data_upper_limit as "Upper Limit",
246+
rule_in_control as "In Control?",
247+
rule_out_of_control_upper as "Out of Control Upper?"
247248
from spc_reports.x_bar_r_rules
248-
where control_window_id = 2
249-
and control_status != 'in_control'
250-
order by sample_id;
249+
where id_control_window = 2
250+
and not rule_in_control
251+
order by id_sample;
251252
```
252253

253254
Giving:
254255

255-
| Sample ID | Sample Average | Upper Limit | Control Status |
256-
|-----------|----------------|-------------|----------------|
257-
| 43 | 1.69696 | 1.693224336 | out_of_control_upper |
258-
| 45 | 1.77 | 1.693224336 | out_of_control_upper |
256+
| Sample ID | Sample Average | Upper Limit | In Control? | Out of Control Upper? |
257+
|-----------|----------------|-------------|-------------|-----------------------|
258+
| 43 | 1.69696 | 1.693224336 | false | true |
259+
| 45 | 1.77 | 1.693224336 | false | true |
259260

260-
We can see that samples 43 and 45 are unusually high: they are `out_of_control_upper`. This means we need to perform an
261+
We can see that samples 43 and 45 are unusually high: they are out of control. This means we need to perform an
261262
investigation to establish what has occurred to cause the unusual sample average.
262263

264+
You may have noticed the prefixes for each column. They follow a consistent pattern across different views and
265+
functions: `id_` refers to an ID from another table, `data_` represents some value as of that sample and `rule_` is
266+
whether a particular rule has been matched or not.
267+
263268
## References and Further Reading
264269

265270
Listed in suggested order of priority.

spec/montgomery_spec.rb

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ class MontgomerySpec < SpcSpec
1313
end
1414

1515
describe "Flow Width example" do
16-
instrument_id = 1
16+
id_instrument = 1
1717

1818
describe "x̄R rules" do
1919
subject do
20-
DB[:x_bar_r_rules].where(instrument_id:)
20+
DB[:x_bar_r_rules].where(id_instrument:)
2121
end
2222

2323
it_has_params(mean: 1.506, upper: 1.693, lower: 1.318)
@@ -29,7 +29,7 @@ class MontgomerySpec < SpcSpec
2929

3030
describe "R̄ rules" do
3131
subject do
32-
DB[:r_rules].where(instrument_id:)
32+
DB[:r_rules].where(id_instrument:)
3333
end
3434

3535
it_has_params(mean: 0.32521, upper: 0.68749, lower: 0)
@@ -39,11 +39,11 @@ class MontgomerySpec < SpcSpec
3939
end
4040

4141
describe "Engine Piston Diameter example" do
42-
instrument_id = 2
42+
id_instrument = 2
4343

4444
describe "x̄s rules" do
4545
subject do
46-
DB[:x_bar_s_rules].where(instrument_id:)
46+
DB[:x_bar_s_rules].where(id_instrument:)
4747
end
4848

4949
it_has_params(mean: 74.001, upper: 74.014, lower: 73.988)
@@ -53,7 +53,7 @@ class MontgomerySpec < SpcSpec
5353

5454
describe "s̄ rules" do
5555
subject do
56-
DB[:s_rules].where(instrument_id:)
56+
DB[:s_rules].where(id_instrument:)
5757
end
5858

5959
it_has_params(mean: 0.0094, upper: 0.0196, lower: 0)
@@ -63,11 +63,11 @@ class MontgomerySpec < SpcSpec
6363
end
6464

6565
describe "Orange Juice Can Inspection" do
66-
instrument_id = 3
66+
id_instrument = 3
6767

6868
describe "p non-conformant rules" do
6969
subject do
70-
DB[:p_non_conformant_rules].where(instrument_id:)
70+
DB[:p_non_conformant_rules].where(id_instrument:)
7171
end
7272

7373
it_has_params(mean: 0.2313, upper: 0.4102, lower: 0.0524)
@@ -79,7 +79,7 @@ class MontgomerySpec < SpcSpec
7979

8080
describe "np non-conformant rules" do
8181
subject do
82-
DB[:np_non_conformant_rules].where(instrument_id:)
82+
DB[:np_non_conformant_rules].where(id_instrument:)
8383
end
8484

8585
it_has_params(mean: 11.565, upper: 20.510, lower: 2.620)
@@ -91,11 +91,11 @@ class MontgomerySpec < SpcSpec
9191
end
9292

9393
describe "Printed Circuit Boards" do
94-
instrument_id = 4
94+
id_instrument = 4
9595

9696
describe "c rules" do
9797
subject do
98-
DB[:c_rules].where(instrument_id:)
98+
DB[:c_rules].where(id_instrument:)
9999
end
100100

101101
it_has_params(mean: 19.85, upper: 33.22, lower: 6.48)
@@ -107,11 +107,11 @@ class MontgomerySpec < SpcSpec
107107
end
108108

109109
describe "Mortgage Loan Cost" do
110-
instrument_id = 5
110+
id_instrument = 5
111111

112112
describe "XmR X rules" do
113113
subject do
114-
DB[:xmr_x_rules].where(instrument_id:)
114+
DB[:xmr_x_rules].where(id_instrument:)
115115
end
116116

117117
it_has_params(mean: 300.5, upper: 321.22, lower: 279.78)
@@ -123,19 +123,19 @@ class MontgomerySpec < SpcSpec
123123

124124
describe "XmR MR rules" do
125125
subject do
126-
DB[:xmr_mr_rules].where(instrument_id:)
126+
DB[:xmr_mr_rules].where(id_instrument:)
127127
end
128128

129129
it_has_params(mean: 7.79, upper: 25.45, lower: 0)
130130

131-
it_has_status_counts_of(in_control: 39, out_of_control_upper: 1, out_of_control_lower: 0)
131+
it_has_status_counts_of(in_control: 38, out_of_control_upper: 1, out_of_control_lower: 0)
132132

133133
it_is_out_of_control_at(upper_samples: [165], lower_samples: [])
134134
end
135135
end
136136

137137
describe "Normal Distribution With Shifting Mean" do
138-
instrument_id = 6
138+
id_instrument = 6
139139

140140
describe "EWMA with fixed targets" do
141141
subject do
@@ -146,7 +146,7 @@ class MontgomerySpec < SpcSpec
146146
10, # target mean
147147
1 # target std dev
148148
)
149-
).where(instrument_id:).order_by(:sample_id)
149+
).where(id_instrument:).order_by(:id_sample)
150150
end
151151

152152
it_has_params(mean: 10, upper: 10.27, lower: 9.73)
@@ -156,7 +156,7 @@ class MontgomerySpec < SpcSpec
156156
it_is_out_of_control_at(upper_samples: [195, 196], lower_samples: [])
157157

158158
# @formatter:off
159-
it_has_correct_values(column: :exponentially_weighted_moving_average, values: [
159+
it_has_correct_values(column: :data_exponentially_weighted_moving_average, values: [
160160
9.945, 9.7495, 9.70355, 9.8992, 10.1253, 10.1307, 9.92167, 10.0755, 9.98796, 10.0232,
161161
9.92384, 10.0785, 10.1216, 10.0495, 10.0525, 9.98426, 10.0478, 10.074, 9.91864, 10.0108,
162162
10.0997, 10.0227, 10.2495, 10.3745, 10.3971, 10.4654, 10.4568, 10.5731, 10.6468, 10.6341
@@ -171,15 +171,15 @@ class MontgomerySpec < SpcSpec
171171
0.1, # weighting
172172
2.7 # limits
173173
)
174-
).where(instrument_id:).order_by(:sample_id)
174+
).where(id_instrument:).order_by(:id_sample)
175175
end
176176

177177
it_has_params(mean: 10.315, upper: 10.626, lower: 10.004)
178178

179179
it_has_status_counts_of(in_control: 30, out_of_control_upper: 0, out_of_control_lower: 0)
180180

181181
# @formatter:off
182-
it_has_correct_values(column: :exponentially_weighted_moving_average, values: [
182+
it_has_correct_values(column: :data_exponentially_weighted_moving_average, values: [
183183
10.2285, 10.0046, 9.93318, 10.1058, 10.3112, 10.2981, 10.0723, 10.2111, 10.1099, 10.1329,
184184
10.0226, 10.1674, 10.2016, 10.1215, 10.1173, 10.0426, 10.1003, 10.1213, 9.96119, 10.0490,
185185
10.1341, 10.0537, 10.2773, 10.3996, 10.4196, 10.4857, 10.4751, 10.5896, 10.6616, 10.6474
@@ -195,11 +195,11 @@ class MontgomerySpec < SpcSpec
195195
5, # decision interval
196196
10 # target mean
197197
)
198-
).where(instrument_id:).order_by(:sample_id)
198+
).where(id_instrument:).order_by(:id_sample)
199199
end
200200

201201
describe "Calculating net deviation" do
202-
it_has_correct_values(column: :deviation, values: [
202+
it_has_correct_values(column: :data_deviation, values: [
203203
# @formatter:off
204204
-0.55, -2.01, -0.71, 1.66, 2.16,
205205
0.18, -1.96, 1.46, -0.8, 0.34,
@@ -212,7 +212,7 @@ class MontgomerySpec < SpcSpec
212212
end
213213

214214
describe "Calculating Cₙ" do
215-
it_has_correct_values(column: :c_n, values: [
215+
it_has_correct_values(column: :data_c_n, values: [
216216
# @formatter:off
217217
-0.55, -2.56, -3.27, -1.61, 0.55,
218218
0.73, -1.23, 0.23, -0.57, -0.23,
@@ -225,7 +225,7 @@ class MontgomerySpec < SpcSpec
225225
end
226226

227227
describe "Calculating positive deviation" do
228-
it_has_correct_values(column: :deviation_plus, values: [
228+
it_has_correct_values(column: :data_deviation_plus, values: [
229229
# @formatter:off
230230
-1.05, -2.51, -1.21, 1.16, 1.66,
231231
-0.32, -2.46, 0.96, -1.3, -0.16,
@@ -238,7 +238,7 @@ class MontgomerySpec < SpcSpec
238238
end
239239

240240
describe "Calculating C⁺" do
241-
it_has_correct_values(column: :c_plus, values: [
241+
it_has_correct_values(column: :data_c_plus, values: [
242242
# @formatter:off
243243
0, 0, 0, 1.16, 2.82,
244244
2.50, 0.04, 1.00, 0, 0,
@@ -251,7 +251,7 @@ class MontgomerySpec < SpcSpec
251251
end
252252

253253
describe "Calculating negative deviation" do
254-
it_has_correct_values(column: :deviation_minus, values: [
254+
it_has_correct_values(column: :data_deviation_minus, values: [
255255
# @formatter:off
256256
-0.05, -1.51, -0.21, 2.16, 2.66,
257257
0.68, -1.46, 1.96, -0.3, 0.84,
@@ -264,7 +264,7 @@ class MontgomerySpec < SpcSpec
264264
end
265265

266266
describe "Calculating C⁻" do
267-
it_has_correct_values(column: :c_minus, values: [
267+
it_has_correct_values(column: :data_c_minus, values: [
268268
# @formatter:off
269269
-0.05, -1.56, -1.77, 0, 0,
270270
0, -1.46, 0, -0.3, 0,

spec/spc_spec.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,46 @@ def run(*args, &block)
1919

2020
def self.it_has_params(mean:, upper:, lower:)
2121
it "has the correct mean" do
22-
assert_in_delta mean, subject.first[:center_line], 0.01
22+
assert_in_delta mean, subject.first[:data_center_line], 0.01
2323
end
2424

2525
it "has the correct upper limit" do
26-
assert_in_delta upper, subject.first[:upper_limit], 0.01
26+
assert_in_delta upper, subject.first[:data_upper_limit], 0.01
2727
end
2828

2929
it "has the correct lower limit" do
30-
assert_in_delta lower, subject.first[:lower_limit], 0.01
30+
assert_in_delta lower, subject.first[:data_lower_limit], 0.01
3131
end
3232
end
3333

3434
def self.it_has_status_counts_of(in_control:, out_of_control_upper:, out_of_control_lower:)
3535
it "has the correct number of in-control points" do
36-
assert_equal in_control, subject.where(control_status: "in_control").count
36+
assert_equal in_control, subject.where(rule_in_control: true).count
3737
end
3838

3939
it "has the correct number of out-of-control-upper points" do
40-
assert_equal out_of_control_upper, subject.where(control_status: "out_of_control_upper").count
40+
assert_equal out_of_control_upper, subject.where(rule_out_of_control_upper: true).count
4141
end
4242

4343
it "has the correct number of out-of-control-lower points" do
44-
assert_equal out_of_control_lower, subject.where(control_status: "out_of_control_lower").count
44+
assert_equal out_of_control_lower, subject.where(rule_out_of_control_lower: true).count
4545
end
4646
end
4747

4848
def self.it_is_out_of_control_at(upper_samples:, lower_samples:)
49-
upper_samples.each do |sample_id|
50-
it "it is out-of-control-upper at sample #{sample_id}" do
51-
control_status = subject.where(sample_id: sample_id).select(:control_status).first
52-
refute_nil control_status, "no matching out-of-control-upper sample was found for #{sample_id}"
53-
assert_equal "out_of_control_upper", control_status[:control_status]
49+
upper_samples.each do |id_sample|
50+
it "it is out-of-control-upper at sample #{id_sample}" do
51+
control_status = subject.where(id_sample:).select(:rule_out_of_control_upper).first
52+
refute_nil control_status, "no matching out-of-control-upper sample was found for #{id_sample}"
53+
assert_equal true, control_status[:rule_out_of_control_upper]
5454
end
5555
end
5656

57-
lower_samples.each do |sample_id|
58-
it "it is out-of-control-lower at sample #{sample_id}" do
59-
control_status = subject.where(sample_id: sample_id).select(:control_status).first
60-
refute_nil control_status, "no matching out-of-control-lower sample was found for #{sample_id}"
61-
assert_equal "out_of_control_lower", control_status[:control_status]
57+
lower_samples.each do |id_sample|
58+
it "it is out-of-control-lower at sample #{id_sample}" do
59+
control_status = subject.where(id_sample:).select(:rule_out_of_control_lower).first
60+
refute_nil control_status, "no matching out-of-control-lower sample was found for #{id_sample}"
61+
assert_equal true, control_status[:rule_out_of_control_lower]
6262
end
6363
end
6464
end

0 commit comments

Comments
 (0)