Skip to content
Snippets Groups Projects
Commit 7765e689 authored by Steve Reis's avatar Steve Reis
Browse files

Merge branch 'feat/integration-logistic-regression' into 'develop'

Integration logistic regression algorithm

See merge request sibmip/gateway!74
parents 4690ffeb 2bc86316
No related branches found
No related tags found
No related merge requests found
...@@ -83,9 +83,6 @@ describe('Linear regression CV result handler', () => { ...@@ -83,9 +83,6 @@ describe('Linear regression CV result handler', () => {
const dataPoints = experiment.results[0] as TableResult; const dataPoints = experiment.results[0] as TableResult;
const scoresData = experiment.results[1] as TableResult; const scoresData = experiment.results[1] as TableResult;
console.log(JSON.stringify(dataPoints));
console.log(JSON.stringify(scoresData));
expect(dataPoints.data).toStrictEqual(expectedDataPoints); expect(dataPoints.data).toStrictEqual(expectedDataPoints);
expect(scoresData.data).toStrictEqual(expectedScoresData); expect(scoresData.data).toStrictEqual(expectedScoresData);
......
import { Domain } from 'src/engine/models/domain.model'; import { Domain } from '../../../../models/domain.model';
import { Experiment } from '../../../../models/experiment/experiment.model'; import { Experiment } from '../../../../models/experiment/experiment.model';
import LinearRegressionHandler from './linear-regression.handler'; import LinearRegressionHandler from './linear-regression.handler';
......
import { Domain } from 'src/engine/models/domain.model'; import { Domain } from '../../../../models/domain.model';
import { Variable } from 'src/engine/models/variable.model'; import { Variable } from '../../../../models/variable.model';
import { isNumber } from '../../../../../common/utils/shared.utils'; import { isNumber } from '../../../../../common/utils/shared.utils';
import { Experiment } from '../../../../models/experiment/experiment.model'; import { Experiment } from '../../../../models/experiment/experiment.model';
import { import {
...@@ -31,7 +31,7 @@ const lookupDict = { ...@@ -31,7 +31,7 @@ const lookupDict = {
export default class LinearRegressionHandler extends BaseHandler { export default class LinearRegressionHandler extends BaseHandler {
private getModel(data: any): TableResult | undefined { private getModel(data: any): TableResult | undefined {
const excepts = ['n_obs']; const exclude = ['n_obs'];
const tableModel: TableResult = { const tableModel: TableResult = {
name: 'Model', name: 'Model',
tableStyle: TableStyle.DEFAULT, tableStyle: TableStyle.DEFAULT,
...@@ -48,7 +48,7 @@ export default class LinearRegressionHandler extends BaseHandler { ...@@ -48,7 +48,7 @@ export default class LinearRegressionHandler extends BaseHandler {
'f_pvalue', 'f_pvalue',
].map((name) => [ ].map((name) => [
lookupDict[name], lookupDict[name],
isNumber(data[name]) && !excepts.includes(name) isNumber(data[name]) && !exclude.includes(name)
? data[name].toPrecision(NUMBER_PRECISION) ? data[name].toPrecision(NUMBER_PRECISION)
: data[name], : data[name],
]), ]),
......
import { Domain } from '../../../../models/domain.model';
import { Experiment } from '../../../../models/experiment/experiment.model';
import LogisticRegressionHandler from './logistic-regression.handler';
const data = [
{
dependent_var: 'ppmicategory',
indep_vars: ['Intercept', 'righthippocampus'],
summary: {
n_obs: 714,
coefficients: [2.6245273240614644, -1.392061918138407],
stderr: [1.3675179284969878, 0.41070496937876727],
lower_ci: [-0.05575856400545254, -2.197028866392417],
upper_ci: [5.304813212128382, -0.5870949698843975],
z_scores: [1.9191904320742843, -3.389445032145682],
pvalues: [0.05496023796478015, 0.0007003424825299484],
df_model: 1,
df_resid: 712,
r_squared_cs: 0.016553598383202917,
r_squared_mcf: 0.02359922514841184,
ll0: -252.5122763647322,
ll: -246.55318230206288,
aic: 497.10636460412576,
bic: 506.24813052880495,
},
},
];
const domain: Domain = {
id: 'dummy-id',
groups: [],
rootGroup: {
id: 'dummy-id',
},
datasets: [{ id: 'desd-synthdata', label: 'Dead Synthdata' }],
variables: [
{ id: 'ppmicategory', label: 'PPMI Category' },
{ id: 'righthippocampus', label: 'Right Hippo Campus' },
],
};
const createExperiment = (): Experiment => ({
id: 'dummy-id',
name: 'Testing purpose',
algorithm: {
name: 'LOGISTIC_REGRESSION',
},
datasets: ['desd-synthdata'],
domain: 'dementia',
variables: ['ppmicategory'],
coVariables: ['righthippocampus'],
results: [],
});
describe('Logistic Regression result Handler', () => {
let logisticHandler: LogisticRegressionHandler;
let experiment: Experiment;
beforeEach(() => {
logisticHandler = new LogisticRegressionHandler();
experiment = createExperiment();
});
describe('handle', () => {
it('with standard logistic algo data', () => {
logisticHandler.handle(experiment, data, domain);
const json = JSON.stringify(experiment.results);
expect(json.includes(domain.variables[0].label)).toBeTruthy();
expect(experiment.results.length).toBe(2);
});
it('Should be empty with another algo', () => {
experiment.algorithm.name = 'dummy_algo';
logisticHandler.handle(experiment, data, domain);
expect(experiment.results.length).toBe(0);
});
});
});
import { isNumber } from '../../../../../common/utils/shared.utils';
import { Domain } from '../../../../models/domain.model';
import { Experiment } from '../../../../models/experiment/experiment.model';
import {
TableResult,
TableStyle,
} from '../../../../models/result/table-result.model';
import BaseHandler from '../base.handler';
const lookupDict = {
dependent_var: 'Dependent variable',
indep_vars: 'Independent variables',
n_obs: 'Number of observations',
df_resid: 'Residual degrees of freedom',
df_model: 'Model degrees of freedom',
coefficients: 'Coefficients',
stderr: 'Std.Err.',
z_scores: 'z-scores',
pvalues: 'P{>|z|}',
lower_ci: 'Lower 95% c.i.',
upper_ci: 'Upper 59% c.i.',
r_squared_mcf: 'McFadden R^2',
r_squared_cs: 'Cox-Snell R^2',
ll0: 'log(L) of null-model',
ll: 'log(L)',
aic: 'AIC',
bic: 'BIC',
};
const EXCLUDE_NUMBER_LIST = ['n_obs', 'df_resid', 'df_model'];
const NUMBER_PRECISION = 4;
const roundNumber = (val: any, name: string) =>
isNumber(val) && !EXCLUDE_NUMBER_LIST.includes(name)
? val.toPrecision(NUMBER_PRECISION)
: val;
export default class LogisticRegressionHandler extends BaseHandler {
private getModel(data: any): TableResult | undefined {
return {
name: 'Model',
tableStyle: TableStyle.DEFAULT,
headers: ['Name', 'Value'].map((name) => ({ name, type: 'string' })),
data: [
'dependent_var',
'n_obs',
'df_resid',
'df_model',
'df_model',
'r_squared_mcf',
'r_squared_cs',
'll0',
'll',
'aic',
'bic',
].map((name) => [lookupDict[name], roundNumber(data[name], name)]),
};
}
private getCoefficients(data: any): TableResult | undefined {
const fields = [
'indep_vars',
'coefficients',
'stderr',
'z_scores',
'pvalues',
'lower_ci',
'upper_ci',
];
return {
name: 'Coefficients',
tableStyle: TableStyle.DEFAULT,
headers: fields.map((name) => ({
name: lookupDict[name],
type: 'string',
})),
data: [fields.map((name) => roundNumber(data[name], name))],
};
}
canHandle(exp: Experiment, data: any): boolean {
return (
exp.algorithm.name.toLowerCase() === 'logistic_regression' &&
!!data &&
!!data[0] &&
!!data[0]['summary']
);
}
handle(experiment: Experiment, data: any, domain?: Domain): void {
if (!this.canHandle(experiment, data))
return super.handle(experiment, data, domain);
const extractedData = {
...data[0],
...data[0]['summary'],
summary: undefined,
};
const varIds = [...experiment.variables, ...(experiment.coVariables ?? [])];
const variables = domain.variables.filter((v) => varIds.includes(v.id));
let jsonData = JSON.stringify(extractedData);
variables.forEach((v) => {
const regEx = new RegExp(v.id, 'gi');
jsonData = jsonData.replaceAll(regEx, v.label);
});
const improvedData = JSON.parse(jsonData);
const model = this.getModel(improvedData);
if (model) experiment.results.push(model);
const coefs = this.getCoefficients(improvedData);
if (coefs) experiment.results.push(coefs);
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment