Skip to content

Commit e7f3b1a

Browse files
authored
Cochran Test (breaking change) (#10)
* change cochran test algorithm * bump version
1 parent b60914d commit e7f3b1a

File tree

4 files changed

+76
-45
lines changed

4 files changed

+76
-45
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "labkar-algorithms",
3-
"version": "3.3.0",
3+
"version": "4.0.0",
44
"description": "Labkar Algorithms",
55
"main": "dist/lib.js",
66
"author": "ODTÜ PAL",

src/algorithms/cochran.ts

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,57 @@
11
import { get } from 'lodash';
22
import { CochranResult } from '../types';
3-
import { standardDeviation } from 'simple-statistics';
3+
import { sampleStandardDeviation } from 'simple-statistics';
44
import cochranCriticalValues from './cochranCriticalValues';
55

6-
export function Cochran(values: Array<number[]>): CochranResult | null {
6+
export function Cochran(
7+
values: Array<number[]>,
8+
options: { alpha: number } = { alpha: 0.05 }
9+
): CochranResult | null {
710
/* p -> numune sayısı */
811
const pValue = values.length;
912

1013
/* n -> yapılan tekrar,test sayısı */
1114
const nValue = values[0].length;
1215

13-
const onePercentCriticalValue = get(
14-
cochranCriticalValues,
15-
`${nValue}.1%.${pValue}`
16-
);
16+
const criticalValueKey =
17+
options.alpha === 0.05
18+
? `${nValue}.5%.${pValue}`
19+
: `${nValue}.1%.${pValue}`;
1720

18-
const fivePercentCriticalValue = get(
19-
cochranCriticalValues,
20-
`${nValue}.5%.${pValue}`
21-
);
21+
const criticalValue = get(cochranCriticalValues, criticalValueKey);
2222

23-
if (!onePercentCriticalValue || !fivePercentCriticalValue) {
23+
if (!criticalValue) {
2424
return null;
2525
}
2626

2727
const squareDeviations = values
28-
.map((value) => {
29-
return standardDeviation(value);
30-
})
31-
.map((value) => {
32-
return value * value;
33-
});
28+
.map((pair: number[]) => sampleStandardDeviation(pair))
29+
.map((sd: number) => sd * sd);
3430

3531
const maxDeviation = Math.max.apply(null, squareDeviations);
3632
const sumOfSquareDeviations = squareDeviations.reduce((a, b) => a + b, 0);
3733

38-
const cValue = maxDeviation / sumOfSquareDeviations;
39-
40-
if (cValue < fivePercentCriticalValue) {
41-
return CochranResult.Correct;
42-
}
34+
// These are the values used to calculate max deviation
35+
const cPairIndex = squareDeviations.indexOf(maxDeviation);
36+
const cPair = values[squareDeviations.indexOf(maxDeviation)];
4337

44-
if (cValue < onePercentCriticalValue && cValue > fivePercentCriticalValue) {
45-
return CochranResult.Straggler;
46-
}
38+
const cValue = maxDeviation / sumOfSquareDeviations;
4739

48-
if (cValue > onePercentCriticalValue) {
49-
return CochranResult.Outlier;
40+
if (cValue < criticalValue) {
41+
return {
42+
outlier: false,
43+
cValue,
44+
cPair,
45+
cPairIndex: cPairIndex,
46+
maxDeviation,
47+
};
5048
}
5149

52-
return null;
50+
return {
51+
outlier: true,
52+
cValue,
53+
cPair,
54+
cPairIndex,
55+
maxDeviation,
56+
};
5357
}

src/types.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,25 @@ export type AResult = {
1010
lowLimit: number;
1111
};
1212

13-
export enum CochranResult {
14-
Outlier = 'outlier',
15-
Straggler = 'straggler',
16-
Correct = 'correct',
17-
}
13+
export type CochranResult = {
14+
outlier: boolean;
15+
/**
16+
* Value used to compare to the elected critical value
17+
*/
18+
cValue: number;
19+
/**
20+
* The pair used to calculate the max deviation
21+
*/
22+
cPair: number[];
23+
/**
24+
* Index of the pair used to calculate the max deviation
25+
*/
26+
cPairIndex: number;
27+
/**
28+
* Maximum value among (stdDev(pair) ^ 2)
29+
*/
30+
maxDeviation: number;
31+
};
1832

1933
export type ReferenceResult = {
2034
value: number;

tests/cochran.test.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Cochran } from '../src/lib';
2-
import { CochranResult } from '../src/types';
32

43
describe('Cochran Algorithm', () => {
54
it('Cochran Algorithm Test (Outlier)', () => {
@@ -21,21 +20,35 @@ describe('Cochran Algorithm', () => {
2120
[88.8, 85],
2221
];
2322

24-
const output = Cochran(samples);
25-
expect(output).toBe(CochranResult.Outlier);
23+
let output = Cochran(samples, { alpha: 0.05 });
24+
expect(output?.maxDeviation).toBeCloseTo(31.205, 3);
25+
expect(output?.cPairIndex).toBe(11);
26+
expect(output?.cPair).toEqual([91, 83.1]);
27+
expect(output?.outlier).toBe(true);
28+
29+
output = Cochran(samples, { alpha: 0.01 });
30+
expect(output?.outlier).toBe(true);
2631
});
2732

28-
it('Cochran Algorithm Test (Correct)', () => {
33+
it.only('Cochran Algorithm Test (Straggler)', () => {
2934
const samples = [
30-
[73, 45],
31-
[22, 26],
32-
[12, 42],
33-
[42, 20],
34-
[21, 30],
35+
[9.9, 10.2],
36+
[10.4, 9.5],
37+
[10, 10],
38+
[10, 10],
39+
[10.2, 10.3],
40+
[9.5, 9.9],
41+
[10.5, 10.1],
42+
[10.1, 10.3],
43+
[10, 10.1],
44+
[10.2, 10],
3545
];
3646

37-
const output = Cochran(samples);
38-
expect(output).toBe(CochranResult.Correct);
47+
let output = Cochran(samples);
48+
expect(output?.outlier).toBe(true);
49+
50+
output = Cochran(samples, { alpha: 0.01 });
51+
expect(output?.outlier).toBe(false);
3952
});
4053

4154
it('Cochran Algorithm Test (Null)', () => {

0 commit comments

Comments
 (0)