#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the
# Apode Project (https://github.com/ngrion/apode).
# Copyright (c) 2020, Néstor Grión and Sofía Sappia
# License: MIT
# Full Text: https://github.com/ngrion/apode/blob/master/LICENSE.txt
# =============================================================================
# DOCS
# =============================================================================
"""Poverty measures for Apode."""
# =============================================================================
# IMPORTS
# =============================================================================
import attr
import numpy as np
# =============================================================================
# FUNCTIONS
# =============================================================================
[docs]@attr.s(frozen=True)
class PovertyMeasures:
"""Poverty Measures.
The following poverty measures are implemented:
- headcount: Headcount Index
- gap: Poverty gap Index
- severity: Poverty Severity Index
- fgt: Foster–Greer–Thorbecke Indices
- sen: Sen Index
- sst: Sen-Shorrocks-Thon Index
- watts: Watts Index
- cuh: Clark, Ulph and Hemming Indices
- takayama: Takayama Index
- kakwani: Kakwani Indices
- thon: Thon Index
- bd: Blackorby and Donaldson Indices
- hagenaars: Hagenaars Index
- chakravarty: Chakravarty Indices
Parameters
----------
method : String
Poverty measure.
**kwargs
Arbitrary keyword arguments.
"""
idf = attr.ib()
def __call__(self, method=None, **kwargs):
"""Return the ApodeData object."""
method = "headcount" if method is None else method
method_func = getattr(self, method)
return method_func(**kwargs)
[docs] def headcount(self, pline=None, factor=1.0, q=None):
"""Headcount index.
The headcount index measures the proportion of the population that
counted as poor. [18]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure.
References
----------
.. [18] Haughton, J., and Khandker, S. R. (2009). Handbook on poverty
and inequality. Washington, DC: World Bank.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
return q / n
[docs] def gap(self, pline=None, factor=1.0, q=None):
"""Poverty gap index.
The poverty gap index adds up the extent to which individuals
on average fall below the poverty line, and expresses it as
a percentage of the poverty line. [19]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure [0, 1].
References
----------
.. [19] Haughton, J., and Khandker, S. R. (2009). Handbook on poverty
and inequality. Washington, DC: World Bank.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
if q == 0:
return 0.0
yp = ys[0:q]
br = (pline - yp) / pline
return np.sum(br) / n
[docs] def severity(self, pline=None, factor=1.0, q=None):
"""Squared Poverty Gap (Poverty Severity) Index.
To construct a measure of poverty that takes into account inequality
among the poor, some researchers use the squared poverty gap index.
This is simply a weighted sum of poverty gaps (as a proportion of the
poverty line), where the weights are the proportionate poverty gaps
themselves. [20]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure in [0, 1].
References
----------
.. [20] Haughton, J., and Khandker, S. R. (2009). Handbook on poverty
and inequality. Washington, DC: World Bank.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
if q == 0:
return 0.0
yp = ys[0:q]
br = np.power((pline - yp) / pline, 2)
return np.sum(br) / n
[docs] def fgt(self, pline=None, alpha=0, factor=1.0, q=None):
"""Foster–Greer–Thorbecke Indices.
When parameter α = 0, P0 is simply the headcount index. When α = 1,
the index is the poverty gap index P1, and when α is set equal
to 2, P2 is the poverty severity index.
A α se le conoce con el nombre de parámetro de aversión a la pobreza y,
por tanto, cuanto mayor sea α, más énfasis se le da al más pobre de
los pobres. [21]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
alpha: float, optional(default=0)
Aversion poverty parameter.
Return
------
out: float
Index measure in [0, 1].
References
----------
.. [21] Foster, J.E.; Greer, J. y Thorbecke, E. (1984). “A class of
decomposable poverty measures”. Econometrica. Vol. 52, n 3,
pp.761–766.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
if q == 0:
return 0.0
yp = ys[0:q]
if alpha < 0:
raise ValueError(f"'alpha' must be >= 0. Found '{alpha}'")
elif alpha == 0:
return q / n
elif alpha == 1:
br = (pline - yp) / pline
return np.sum(br) / n
br = np.power((pline - yp) / pline, alpha)
return np.sum(br) / n
[docs] def sen(self, pline=None, factor=1.0, q=None):
"""Sen Index.
Sen (1976) proposed an index that seeks to combine the effects of the
number of poor, the depth of their poverty, and the distribution
poverty within the group. [22]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure in [0, 1].
References
----------
.. [22] Sen, A. (1976). “Poverty: an ordinal approach to measurement”.
Econometrica 44(2), pp.219–231.
"""
p0 = self.headcount(pline=pline, factor=factor, q=q)
p1 = self.gap(pline=pline, factor=factor, q=q)
gp = self.idf.inequality.gini()
return p0 * gp + p1 * (1 - gp)
[docs] def sst(self, pline=None, factor=1.0, q=None):
"""Sen-Shorrocks-Thon Index Index.
The Sen index has been modified by others, and one of the
most attractive versions is the Sen-Shorrocks-Thon (SST)
index. One strength of the SST index is that it can help
give a good sense of the sources of change in poverty over
time. This is because the index can be decomposed. [23]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure.
References
----------
.. [23] Xu, K. (1998). Statistical inference for the Sen-Shorrocks-Thon
index of poverty intensity. Journal of Income Distribution, 8,
143-152.
"""
from .basic import ApodeData # noqa
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
if np.sum(y < pline) == 0:
return 0.0
p0 = self.headcount(pline=pline)
ad_p = self.idf[y < pline]
p1p = ad_p.poverty.gap(pline=pline)
gr = np.maximum((pline - y) / pline, 0)
ad_gr = ApodeData({"x": gr}, income_column="x") # noqa
gp = ad_gr.inequality.gini()
return p0 * p1p * (1 + gp)
[docs] def watts(self, pline=None, factor=1.0, q=None):
"""Watts index.
Harold Watts (1968) propuso la siguiente medida de
pobreza sensible a la distribución de rentas. [24]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure [0,inf].
References
----------
.. [24] Watts, H. (1968). “An economic definition of poverty”, en D. P.
Moynihan. On Understanding Poverty. Basic Books. Inc. New York,
pp.316–329.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
yp = ys[0:q]
return sum(np.log(pline / yp)) / n
[docs] def cuh(self, pline=None, alpha=0.5, factor=1.0, q=None):
"""Clark, Ulph and Hemming index.
Clark, Hemming y Ulph (1981) proponen utilizar en la medida
de pobreza de Sen, la medida de Atkinson en lugar del índice
de Gini de los pobres. [25]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
alpha: float, optional(default=0.5)
Atkinson parameter.
Return
------
out: float
Index measure in [0,1].
References
----------
.. [25] Clark, S.R.; Hemming, R. y Ulph, D. (1981). “On indices for
the measurement of poverty”. Economic Journal. Vol. 91,
pp.515–526.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
yp = ys[0:q]
if (alpha < 0) or (alpha > 1):
raise ValueError(f"'alpha' must be in [0,1]. Found '{alpha}'")
if alpha == 0:
return 1 - np.exp(np.sum(np.log(yp)) / n) / pline
# return 1 - np.power(np.product(yp / pline) / n, 1 / n)
else:
return np.sum(1 - np.power(yp / pline, alpha)) / (alpha * n)
# return 1 - np.power(
# (sum(np.power(yp / pline, alpha)) + (n - q)) / n, 1 / alpha
# )
[docs] def takayama(self, pline=None, factor=1.0, q=None):
"""Takayama Index.
Takayama (1979) define su medida de pobreza calculando el índice
de Gini de la distribución censurada por la línea de pobreza. [26]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure in [0,1].
References
----------
.. [26] Takayama, N. (1979). “Poverty, income inequality, and their
measures: Professor Sen’s axiomatic approach reconsidered”.
Econometrica. Vol. 47, n 3, pp.747–759.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
if q == 0:
return 0 # CHECK THIS!!
yp = ys[0:q]
u = (yp.sum() + (n - q) * pline) / n
if u == 0 or n == 0:
return 0 # to avoid NaNs for zero division error
# i_0q = np.arange(q)
# i_qn = np.arange(q, n)
i_0q = np.arange(1, q + 1)
i_qn = np.arange(q + 1, n + 1)
a = np.sum(np.dot(n - i_0q + 1, ys[:q])) + np.sum(
(n - i_qn + 1) * pline
) # )
return 1 + 1 / n - (2 / (u * n * n)) * a
# Kakwani Index
[docs] def kakwani(self, pline=None, alpha=2, factor=1.0, q=None):
"""Kakwani Indices.
La familia de Kakwani (1980) que pondera los déficit mediante
una potencia del número de orden que ocupa cada individuo
dentro del subgrupo de pobres. El parámetro α identifica una
cierta “aversión” al lugar ocupado en la sociedad. [27]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
alpha: float, optional(default=2)
Aversion parameter.
Return
------
out: float
Index measure in [0, 1].
References
----------
.. [27] Kakwani, Nanak (1980). “On a Class of Poverty Measures”.
Econometrica, vol.48, n.2, pp.437-446
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
ii = np.arange(q)
f = np.power(q - ii + 2, alpha)
a = np.float(np.sum(f))
u = np.sum(np.dot(f, pline - ys[:q]))
if u == 0:
return 0 # to avoid NaNs for zero division error
return (q / (n * pline * a)) * u
[docs] def thon(self, pline=None, factor=1.0, q=None):
"""Thon Index.
La diferencia entre esta medida (Thon,1979) y la de Sen radica
en la función de ponderación. Aquí se pondera el individuo pobre
por el lugar que ocupa dentro de toda la población, y no solo
respecto a los pobres. [28]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure.
References
----------
.. [28] Thon, D. (1979). “On measuring poverty”. Review of Income
and Wealth. Vol. 25, pp.429–439.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
ii = np.arange(1, q + 1)
u = np.sum(np.dot(n - ii + 1, pline - ys[:q]))
return (2 / (n * (n + 1) * pline)) * u
[docs] def bd(self, pline=None, alpha=2, factor=1.0, q=None):
"""Blackorby and Donaldson Indices.
Blackorby y Donaldson (1980) proponen una medida de pobreza de tipo
normativo. [29]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
alpha: float, optional(default=2)
Aversion parameter. (ver)
Return
------
out: float
Index measure in [0,1].
References
----------
.. [29] Blackorby, C. y Donaldson, D. (1980). “Ethical indices for the
measurement of poverty”. Econometrica. Vol. 48, n 4,
pp.1053–1060.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
if q == 0:
return 0 # CHECK IF CORRECT
yp = ys[0:q]
u = yp.sum() / q
# atkp = atkinson(yp, alpha)
# gp = self.idf.inequality.gini()
# atkp = self.idf.inequality.atkinson(alpha=alpha) # mal
ad_p = self.idf[y < pline]
atkp = ad_p.inequality.atkinson(alpha=alpha)
yedep = u * (1 - atkp)
return (q / n) * (pline - yedep) / pline
[docs] def hagenaars(self, pline=None, factor=1.0, q=None):
"""Hagenaars Index.
Hagenaars (1984) para obtener la medida de pobreza considera
la función de evaluación social de la renta como V(x) = ln(x). [30]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
Return
------
out: float
Index measure [unbounded].
References
----------
.. [30] Hagenaars, A. (1984). “A class of poverty indices”. Center
for Research in Public Economics. Leyden University.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
if q == 0:
return 0 # check this!!
yp = ys[0:q]
# ug = np.exp(sum(np.log(yp)) / q) # o normalizar con el maximo
# return (q / n) * ((np.log(pline) - np.log(ug)) / np.log(pline))
# ver zheng (1997) p153
return np.sum(1 - np.log(yp) / np.log(pline)) / n
[docs] def chakravarty(self, pline=None, alpha=0.5, factor=1.0, q=None):
"""Chakravarty Indices.
Chakravarty (1983) es una medida ética de pobreza. El índice de pobreza
se obtiene como la suma normalizada de las carencias de
utilidad de los pobres. [31]_
Parameters
----------
pline : optional(default=None)
Absolute poverty line if pline is float.
Relative poverty line if pline is 'median', 'quantile' or 'mean'
If pline is None then pline = 0.5*median(y).
factor : float, optional(default=1.0)
Factor in pline = factor*stat
q : float, optional(default=None)
Cuantil q if pline is'quantile'
alpha: float, optional(default=0.5)
Aversion parameter. (ver)
Return
------
out: float
Index measures.
References
----------
.. [31] Chakravarty, S.R. (1983). “A new index of poverty”.
Mathematical Social Sciences. Vol. 6, pp.307–313.
"""
y = self.idf.data[self.idf.income_column].values
pline = _get_pline(y, pline, factor, q)
if (alpha <= 0) or (alpha >= 1):
raise ValueError(f"'alpha' must be in (0,1). Found '{alpha}'")
n = len(y)
ys = np.sort(y)
q = np.sum(ys < pline)
yp = ys[0:q]
return sum(1 - np.power(yp / pline, alpha)) / n
def _get_pline(y, pline, factor, q):
"""Check/calcule poverty line."""
if factor < 0:
raise ValueError(f"'factor' must be <=0. Found '{factor}'")
if pline is None:
return 0.5 * np.median(y)
if pline == "median":
return factor * np.median(y)
elif pline == "mean":
return factor * np.mean(y)
elif pline == "quantile":
if (q < 0) or (q > 1):
raise ValueError(f"Quantile 'q' must be in [0,1]. Found '{q}'")
return factor * np.quantile(y, q=q)
elif pline <= 0:
raise ValueError(f"'pline' must be >= 0. Found '{pline}'")
else:
return pline