Skip to content

Commit

Permalink
use same income distribution as in old model
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow committed Jan 31, 2024
1 parent 34eea60 commit a8ba1e0
Showing 1 changed file with 27 additions and 57 deletions.
84 changes: 27 additions & 57 deletions src/main/java/org/matsim/prepare/population/CalcIncome.java
Original file line number Diff line number Diff line change
@@ -1,83 +1,53 @@
package org.matsim.prepare.population;

import org.apache.commons.math3.distribution.EnumeratedIntegerDistribution;
import org.apache.commons.math3.random.Well19937c;
import org.matsim.api.core.v01.population.Person;
import org.matsim.core.population.PersonUtils;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.population.algorithms.PersonAlgorithm;

import java.util.HashMap;
import java.util.Map;
import java.util.SplittableRandom;
import java.util.stream.IntStream;

/**
* Draw income from distribution, according to household size and income group. Based on SrV income groups.
* Draw income from german wide distribution.
*/
public class CalcIncome implements PersonAlgorithm {

/**
* Income groups in Euro. The last element is the maximum income in the model, which is not known but defined.
* The minimum is also defined as well.
*/
private static final int[] INCOME_GROUPS = new int[]{450, 500, 900, 1500, 2000, 2600, 3000, 3600, 4600, 5600, 8000};

/**
* Distribution per economic status. See python file extract income.
*/
private static final Map<String, double[]> INCOME_DIST = Map.of(
"very_low", new double[]{0.086, 0.342, 0.343, 0.165, 0.058, 0.004, 0.002, 0.000, 0.000, 0.000},
"low", new double[]{0.000, 0.000, 0.443, 0.343, 0.123, 0.031, 0.056, 0.005, 0.000, 0.000},
"medium", new double[]{0.000, 0.000, 0.000, 0.154, 0.324, 0.196, 0.237, 0.084, 0.005, 0.000},
"high", new double[]{0.000, 0.000, 0.000, 0.000, 0.000, 0.066, 0.069, 0.433, 0.377, 0.055},
"very_high", new double[]{0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.025, 0.975}
);

private final SplittableRandom rnd = new SplittableRandom(1234);

private final Map<String, EnumeratedIntegerDistribution> dists = new HashMap<>();


public CalcIncome() {

for (Map.Entry<String, double[]> e : INCOME_DIST.entrySet()) {
EnumeratedIntegerDistribution d = new EnumeratedIntegerDistribution(
new Well19937c(0),
IntStream.range(0, e.getValue().length).toArray(), e.getValue());
dists.put(e.getKey(), d);
}

}

@Override
public void run(Person person) {


// Only handle persons
if (!PopulationUtils.getSubpopulation(person).equals("person"))
return;

int hh = (int) person.getAttributes().getAttribute(Attributes.HOUSEHOLD_SIZE);
String economicStatus = (String) person.getAttributes().getAttribute(Attributes.ECONOMIC_STATUS);

// This is only approximate correct at best, finer grained income data is not available
// Economic status is normally per household and defined here:
// https://tu-dresden.de/bu/verkehr/ivs/srv/ressourcen/dateien/SrV2018_Tabellenbericht_Oberzentren_500TEW-_flach.pdf?lang=de
// page 17

EnumeratedIntegerDistribution dist = dists.get(economicStatus);

int idx = dist.sample();

// income between lower and upper bound is uniformly sampled
int income = rnd.nextInt(INCOME_GROUPS[idx], INCOME_GROUPS[idx + 1]);

// Income is divided equally to household
double perPerson = (double) income / hh;
// The income is german wide and not related to other attributes
// even though srv contains the (household) economic status, this can not be easily back calculated to the income
person.getAttributes().removeAttribute(Attributes.ECONOMIC_STATUS);

// https://de.wikipedia.org/wiki/Einkommensverteilung_in_Deutschland
// besser https://www.destatis.de/DE/Themen/Gesellschaft-Umwelt/Einkommen-Konsum-Lebensbedingungen/Einkommen-Einnahmen-Ausgaben/Publikationen/Downloads-Einkommen/einkommensverteilung-2152606139004.pdf?__blob=publicationFile
// Anteil der Personen (%) an allen Personen 10 20 30 40 50 60 70 80 90 100
// Nettoäquivalenzeinkommen(€) 826 1.142 1.399 1.630 1.847 2.070 2.332 2.659 3.156 4.329

double income = 0.;
double rndDouble = rnd.nextDouble();

if (rndDouble <= 0.1) income = 826.;
else if (rndDouble > 0.1 && rndDouble <= 0.2) income = 1142.;
else if (rndDouble > 0.2 && rndDouble <= 0.3) income = 1399.;
else if (rndDouble > 0.3 && rndDouble <= 0.4) income = 1630.;
else if (rndDouble > 0.4 && rndDouble <= 0.5) income = 1847.;
else if (rndDouble > 0.5 && rndDouble <= 0.6) income = 2070.;
else if (rndDouble > 0.6 && rndDouble <= 0.7) income = 2332.;
else if (rndDouble > 0.7 && rndDouble <= 0.8) income = 2659.;
else if (rndDouble > 0.8 && rndDouble <= 0.9) income = 3156.;
else if (rndDouble > 0.9) income = 4329.;
else {
throw new RuntimeException("Aborting..." + rndDouble);
}

// Minimum income is "Regelsatz"
PersonUtils.setIncome(person, Math.max(450, perPerson));
PersonUtils.setIncome(person, income);
}

}

0 comments on commit a8ba1e0

Please sign in to comment.