Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
21d2181
Person EQ5D column added
andrewbaxter439 Mar 17, 2025
e83cd2a
EQ5D enum added
andrewbaxter439 Mar 17, 2025
d2ea2f9
Added polynomials and interactions for pcs and mcs
andrewbaxter439 Mar 17, 2025
6d89d8a
eq5d coefficient excel sheet
andrewbaxter439 Mar 17, 2025
41d319c
add enum and prediction call in person
andrewbaxter439 Mar 17, 2025
5001f24
add regression processes
andrewbaxter439 Mar 17, 2025
dc9b520
corrected spelling in excel
andrewbaxter439 Mar 17, 2025
3456e7e
add update eq5d
andrewbaxter439 Mar 17, 2025
c8ff3e4
add lower bound to eq5d score
andrewbaxter439 Mar 17, 2025
c359970
add some (failing) person tests
andrewbaxter439 Mar 18, 2025
fe728b8
Further testing for person eq5d - correct calcs
andrewbaxter439 Mar 18, 2025
720061f
Merge branch 'experiment/person_testing' into feature/148-add-eq5d-as…
andrewbaxter439 Mar 18, 2025
0726f14
adding franks coefficients option
andrewbaxter439 Mar 18, 2025
35a6dad
updated tests (running in wrong order)
andrewbaxter439 Mar 18, 2025
28519b0
correct order for EQ5D tests
andrewbaxter439 Mar 18, 2025
90e458b
EQ5D tests trigger events rather than call update methods directly
andrewbaxter439 Mar 18, 2025
9af6fe0
refactored `deq5d` to `he_eq5d` and similar
andrewbaxter439 Mar 18, 2025
fcfd42a
Make aging private
andrewbaxter439 Mar 19, 2025
9b55497
change `healthEQ5D` method to private
andrewbaxter439 Mar 19, 2025
e955154
construct person in setup
andrewbaxter439 Mar 19, 2025
e88c371
rename setup
andrewbaxter439 Mar 19, 2025
92f9364
clearer test naming
andrewbaxter439 Mar 19, 2025
833e645
extract load eq5d parameters as public method
andrewbaxter439 Mar 19, 2025
681bd5b
only re-load eq5d params (and reset)
andrewbaxter439 Mar 19, 2025
9719062
remove test order assertions
andrewbaxter439 Mar 19, 2025
a528a4f
remove redundant re-calling of health regression loading
andrewbaxter439 Mar 19, 2025
cc3063e
simplify not loading all parameters
andrewbaxter439 Mar 20, 2025
cd11f2b
change parameter loading to BeforeEach
andrewbaxter439 Mar 20, 2025
70929ab
add annotation to new Person enums
andrewbaxter439 Mar 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added input/reg_eq5d.xlsx
Binary file not shown.
3 changes: 3 additions & 0 deletions src/main/java/simpaths/data/ManagerRegressions.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public static LinearRegression getLinearRegression(RegressionName regression) {
case LifeSatisfaction2Females -> {
return Parameters.getRegLifeSatisfaction2Females();
}
case HealthEQ5D -> {
return Parameters.getRegEQ5D();
}
case SocialCareS1b -> {
return Parameters.getRegCareHoursS1b();
}
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/simpaths/data/Parameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ else if(numberOfChildren <= 5) {
public static boolean saveImperfectTaxDBMatches = false;
public static final int IMPERFECT_THRESHOLD = 5999;

public static String eq5dConversionParameters = "lawrence";


/////////////////////////////////////////////////////////////////// INITIALISATION OF DATA STRUCTURES //////////////////////////////////
public static Map<Integer, String> EUROMODpolicySchedule = new TreeMap<Integer, String>();
Expand Down Expand Up @@ -472,6 +474,7 @@ else if(numberOfChildren <= 5) {
private static MultiKeyCoefficientMap coeffCovarianceDLS2Males;
private static MultiKeyCoefficientMap coeffCovarianceDLS2Females;

private static MultiKeyCoefficientMap coeffCovarianceEQ5D;

//Education
private static MultiKeyCoefficientMap coeffCovarianceEducationE1a;
Expand Down Expand Up @@ -707,6 +710,8 @@ else if(numberOfChildren <= 5) {
private static LinearRegression regLifeSatisfaction2Males;
private static LinearRegression regLifeSatisfaction2Females;

private static LinearRegression regHealthEQ5D;

//Education
private static BinomialRegression regEducationE1a;
private static BinomialRegression regEducationE1b;
Expand Down Expand Up @@ -972,6 +977,7 @@ public static void loadParameters(Country country, int maxAgeModel, boolean enab
int columnsLifeSatisfaction1 = -1;
int columnsLifeSatisfaction2Males = -1;
int columnsLifeSatisfaction2Females = -1;
int columnsHealthEQ5D = -1;
int columnsSocialCareS1a = -1;
int columnsSocialCareS1b = -1;
int columnsSocialCareS2a = -1;
Expand Down Expand Up @@ -1132,6 +1138,7 @@ else if(country.equals(Country.UK)) {
columnsLifeSatisfaction1 = 30;
columnsLifeSatisfaction2Males = 9;
columnsLifeSatisfaction2Females = 9;
columnsHealthEQ5D = 8;
columnsSocialCareS1a = 17;
columnsSocialCareS1b = 18;
columnsSocialCareS2a = 32;
Expand Down Expand Up @@ -1351,6 +1358,8 @@ else if(country.equals(Country.UK)) {
coeffCovarianceDLS2Males = ExcelAssistant.loadCoefficientMap("input/reg_health_wellbeing.xlsx", countryString + "_DLS2_Males", 1, columnsLifeSatisfaction2Males);
coeffCovarianceDLS2Females = ExcelAssistant.loadCoefficientMap("input/reg_health_wellbeing.xlsx", countryString + "_DLS2_Females", 1, columnsLifeSatisfaction2Females);

loadEQ5DParameters(countryString, columnsHealthEQ5D);

//Life satisfaction

// coeffCovarianceDLS1 = ExcelAssistant.loadCoefficientMap("input/reg_lifesatisfaction.xlsx", countryString + "_DLS1", 1, columnsLifeSatisfaction1);
Expand Down Expand Up @@ -1570,7 +1579,6 @@ else if (country.equals(Country.IT)) {
regLifeSatisfaction2Males = new LinearRegression(coeffCovarianceDLS2Males);
regLifeSatisfaction2Females = new LinearRegression(coeffCovarianceDLS2Females);

//Education
regEducationE1a = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffCovarianceEducationE1a);
regEducationE1b = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffCovarianceEducationE1b);
regEducationE2a = new OrderedRegression<>(RegressionType.GenOrderedLogit, Education.class, coeffCovarianceEducationE2a);
Expand Down Expand Up @@ -2075,6 +2083,8 @@ public static void setEmploymentsFurloughedFlex(MultiKeyCoefficientMap employmen
public static BinomialRegression getRegEducationE1b() {return regEducationE1b;}
public static OrderedRegression getRegEducationE2a() {return regEducationE2a;}

public static LinearRegression getRegEQ5D() { return regHealthEQ5D; };

public static BinomialRegression getRegPartnershipU1a() {return regPartnershipU1a;}
public static BinomialRegression getRegPartnershipU1b() {return regPartnershipU1b;}
public static BinomialRegression getRegPartnershipU2b() {return regPartnershipU2b;}
Expand Down Expand Up @@ -3331,4 +3341,12 @@ private static void safeDelete(String filePath) {
throw e;
}
}

public static void loadEQ5DParameters(String countryString, int columnsHealthEQ5D) {

coeffCovarianceEQ5D = ExcelAssistant.loadCoefficientMap("input/reg_eq5d.xlsx", countryString + "_EQ5D_" + eq5dConversionParameters, 1, columnsHealthEQ5D);

regHealthEQ5D = new LinearRegression(coeffCovarianceEQ5D);

}
}
2 changes: 2 additions & 0 deletions src/main/java/simpaths/data/RegressionName.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public enum RegressionName {
LifeSatisfaction2Males(RegressionType.Linear),
LifeSatisfaction2Females(RegressionType.Linear),

HealthEQ5D(RegressionType.Linear),

RMSE(RegressionType.Linear),

SocialCareS1a(RegressionType.Probit),
Expand Down
89 changes: 89 additions & 0 deletions src/main/java/simpaths/model/Person.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ public class Person implements EventListener, IDoubleSource, IIntSource, Weight,
private Integer dls; //life satisfaction - score 1-7
@Transient private Double dls_temp;
@Transient private Integer dls_lag1; //life satisfaction - score 1-7 lag 1
@Column(name="he_eq5d")
private Double he_eq5d;

@Column(name="dhh_owned") private Boolean dhhOwned; // Person is a homeowner, true / false
@Transient private Boolean receivesBenefitsFlag_L1; // Lag(1) of whether person receives benefits
@Transient private Boolean receivesBenefitsFlag; // Does person receive benefits
Expand Down Expand Up @@ -667,6 +670,7 @@ public enum Processes {
Fertility,
GiveBirth,
Health,
HealthEQ5D,
HealthMentalHM1, //Predict level of mental health on the GHQ-12 Likert scale (Step 1)
HealthMentalHM2, //Modify the prediction from Step 1 by applying increments / decrements for exposure
HealthMentalHM1HM2Cases, //Case-based prediction for psychological distress, Steps 1 and 2 together
Expand Down Expand Up @@ -756,6 +760,9 @@ public void onEvent(Enum<?> type) {
case HealthMentalHM1HM2Cases -> {
healthMentalHM1HM2Cases();
}
case HealthEQ5D -> {
healthEQ5D();
}
case InSchool -> {
// log.debug("In Education for person " + this.getKey().getId());
inSchool();
Expand Down Expand Up @@ -1030,6 +1037,22 @@ protected void lifeSatisfaction2() {
}
}

private void healthEQ5D() {

double eq5dPrediction;
eq5dPrediction = Parameters.getRegEQ5D().getScore(this, Person.DoublesVariables.class);
if (eq5dPrediction > 1) {
he_eq5d = 1.0;
}
else if (eq5dPrediction < -0.594) {
he_eq5d = -0.594;
}
else {
he_eq5d = eq5dPrediction;
}

}

/*
Case-based measure of psychological distress, Steps 1 and 2 modelled together
*/
Expand Down Expand Up @@ -2253,6 +2276,7 @@ public enum DoublesVariables {
Dehmf_c3_Low,
Dehsp_c3_Low_L1, //Partner's education == Low at lag(1)
Dehsp_c3_Medium_L1, //Partner's education == Medium at lag(1)
He_eq5d, //EQ5D quality of life score
Dgn, //Gender: returns 1 if male
Dgn_baseline,
Dgn_Dag,
Expand Down Expand Up @@ -2294,8 +2318,17 @@ public enum DoublesVariables {
Dls_L1, //Life satisfaction status lag(1)
Dhe_mcs, //Mental well-being status
Dhe_mcs_L1, //Mental well-being status lag(1)
Dhe_mcs_sq, //MCS score squared
Dhe_mcs_times_pcs, //MCS times PCS
Dhe_mcs_c_times_pcs_c, //Centralised MCS times PCS
Dhe_mcs_c, //MCS centralised by subtracting population mean
Dhe_mcs_c_sq, //Square of centralised MCS
Dhe_pcs, //Physical well-being status
Dhe_pcs_L1, //Physical well-being status lag(1)
Dhe_pcs_sq, //PCS score squared
Dhe_pcs_cb, //PCS score cubed
Dhe_pcs_c, //MCS centralised by subtracting population mean
Dhe_pcs_c_sq, //Square of centralised MCS
Dhmghq_L1,
Dlltsd, //Long-term sick or disabled
Dlltsd_L1, //Long-term sick or disabled lag(1)
Expand Down Expand Up @@ -2860,6 +2893,26 @@ public double getDoubleValue(Enum<?> variableID) {
return dhe_mcs_lag1;
} else return 0.;
}
case Dhe_mcs_sq -> {
// Used to calculate he_eq5d in regHealthEQ5D
return dhe_mcs * dhe_mcs;
}
case Dhe_mcs_c -> {
// Used to calculate he_eq5d in regHealthEQ5D
return dhe_mcs - 51.5;
}
case Dhe_mcs_c_sq -> {
// Used to calculate he_eq5d in regHealthEQ5D
return Math.pow(dhe_mcs - 51.5, 2);
}
case Dhe_mcs_times_pcs -> {
// Used to calculate he_eq5d in regHealthEQ5D
return dhe_mcs * dhe_pcs;
}
case Dhe_mcs_c_times_pcs_c -> {
// Used to calculate he_eq5d in regHealthEQ5D
return (dhe_mcs - 51.5) * (dhe_pcs - 49.9);
}
case Dhe_pcs -> {
return dhe_pcs;
}
Expand All @@ -2868,6 +2921,22 @@ public double getDoubleValue(Enum<?> variableID) {
return dhe_pcs_lag1;
} else return 0.;
}
case Dhe_pcs_sq -> {
// Used to calculate he_eq5d in regHealthEQ5D
return dhe_pcs * dhe_pcs;
}
case Dhe_pcs_cb -> {
// Used to calculate he_eq5d in regHealthEQ5D
return dhe_pcs * dhe_pcs * dhe_pcs;
}
case Dhe_pcs_c -> {
// Used to calculate he_eq5d in regHealthEQ5D
return dhe_pcs - 49.9;
}
case Dhe_pcs_c_sq -> {
// Used to calculate he_eq5d in regHealthEQ5D
return Math.pow(dhe_pcs - 49.9, 2);
}
case Dls -> {
return dls;
}
Expand Down Expand Up @@ -2933,6 +3002,9 @@ public double getDoubleValue(Enum<?> variableID) {
case Dehsp_c3_Low_L1 -> {
return (Education.Low.equals(dehsp_c3_lag1)) ? 1. : 0.;
}
case He_eq5d -> {
return getHe_eq5d();
}
case Dhhtp_c4_CoupleChildren_L1 -> {
return (Dhhtp_c4.CoupleChildren.equals(getDhhtp_c4_lag1())) ? 1.0 : 0.0;
}
Expand Down Expand Up @@ -4110,6 +4182,15 @@ public double getDhe_pcs() {
return val;
}


public void setDhe_mcs(Double dhe_mcs) {
this.dhe_mcs = dhe_mcs;
}

public void setDhe_pcs(Double dhe_pcs) {
this.dhe_pcs = dhe_pcs;
}

public void populateSocialCareReceipt(SocialCareReceiptState state) {
if (SocialCareReceiptState.NoFormal.equals(state)) {
needSocialCare = Indicator.True;
Expand Down Expand Up @@ -5122,4 +5203,12 @@ public Long getIdFather() {
public boolean getToBePartnered() {return toBePartnered;}

public static void setPersonIdCounter(long id) {personIdCounter=id;}

public Double getHe_eq5d() {
return he_eq5d;
}

public void setHe_eq5d(Double he_eq5d) {
this.he_eq5d = he_eq5d;
}
}
2 changes: 2 additions & 0 deletions src/main/java/simpaths/model/SimPathsModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,8 @@ public void buildSchedule() {
yearlySchedule.addCollectionEvent(persons, Person.Processes.HealthPCS2);
yearlySchedule.addCollectionEvent(persons, Person.Processes.LifeSatisfaction2);

addCollectionEventToAllYears(persons, Person.Processes.HealthEQ5D);

// mortality (migration) and population alignment at year's end
addCollectionEventToAllYears(persons, Person.Processes.ConsiderMortality);
addEventToAllYears(Processes.PopulationAlignment);
Expand Down
110 changes: 110 additions & 0 deletions src/test/java/simpaths/model/PersonTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package simpaths.model;

import org.junit.jupiter.api.*;
import simpaths.data.Parameters;
import simpaths.model.enums.Country;

import static org.junit.jupiter.api.Assertions.*;

@DisplayName("Person class")
public class PersonTest {

static Person testPerson;

@BeforeAll
static void setup() {
testPerson = new Person(true);
}

@Nested
@DisplayName("EQ5D process")
class Eq5dTests {

@Nested
@DisplayName("With eq5dConversionParameters set to 'lawrence'")
class WithLawrenceParameters {

@BeforeEach
public void setupLawrenceCoefficients() {

Parameters.eq5dConversionParameters = "lawrence";
Parameters.loadEQ5DParameters("UK", 8);

}

@Test
@DisplayName("Calculates low score correctly using Lawrence and Fleishman coefficients")
public void calculatesLowScoreCorrectly() {


testPerson.setDhe_mcs(1.);
testPerson.setDhe_pcs(1.);

testPerson.onEvent(Person.Processes.HealthEQ5D);

assertEquals(-0.594, testPerson.getHe_eq5d());

}

@Test
@DisplayName("Calculates high score correctly using Lawrence and Fleishman coefficients")
public void calculatesHighScoreCorrectly() {


testPerson.setDhe_mcs(100.);
testPerson.setDhe_pcs(100.);

testPerson.onEvent(Person.Processes.HealthEQ5D);

assertEquals(1, testPerson.getHe_eq5d());

}

}


@Nested
@DisplayName("With eq5dConversionParameters set to 'franks'")
class WithFranksParameters {

@BeforeEach
public void setupFranksCoefficients() {

Parameters.eq5dConversionParameters = "franks";
Parameters.loadEQ5DParameters("UK", 8);

}


@Test
@DisplayName("Calculates low score correctly using Franks coefficients")
public void calculatesLowScoreCorrectly() {

testPerson.setDhe_mcs(1.);
testPerson.setDhe_pcs(1.);

testPerson.onEvent(Person.Processes.HealthEQ5D);

assertEquals(-0.594, testPerson.getHe_eq5d());

}

@Test
@DisplayName("Calculates high score correctly using Franks coefficients")
public void calculatesHighScoreCorrectly(){

testPerson.setDhe_mcs(100.);
testPerson.setDhe_pcs(100.);

testPerson.onEvent(Person.Processes.HealthEQ5D);

// The maximum possible value given by the Franks coefficients
assertEquals(0.9035601, testPerson.getHe_eq5d());

}

}
}


}