microdf-python 0.4.3__py3-none-any.whl → 0.4.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. microdf/__init__.py +10 -20
  2. microdf/_optional.py +8 -9
  3. microdf/agg.py +12 -15
  4. microdf/concat.py +8 -5
  5. microdf/custom_taxes.py +51 -57
  6. microdf/income_measures.py +10 -11
  7. microdf/inequality.py +71 -22
  8. microdf/io.py +8 -10
  9. microdf/microdataframe.py +501 -0
  10. microdf/microseries.py +625 -0
  11. microdf/poverty.py +11 -12
  12. microdf/tax.py +19 -21
  13. microdf/taxcalc.py +33 -23
  14. microdf/tests/conftest.py +9 -0
  15. microdf/tests/test_compare.py +48 -0
  16. microdf/tests/test_decile_rank.py +91 -0
  17. microdf/tests/test_inequality.py +20 -0
  18. microdf/tests/test_io.py +10 -0
  19. microdf/tests/test_microseries_dataframe.py +290 -0
  20. microdf/tests/test_optional_dependency.py +54 -0
  21. microdf/tests/test_poverty.py +73 -0
  22. microdf/tests/test_quantile_chg.py +14 -0
  23. microdf/tests/test_tax.py +54 -0
  24. microdf/tests/test_taxcalc.py +25 -0
  25. microdf/tests/test_utils.py +39 -0
  26. microdf/tests/test_weighted.py +74 -0
  27. microdf/ubi.py +17 -15
  28. microdf/utils.py +14 -15
  29. microdf/weighted.py +61 -31
  30. microdf_python-0.4.5.dist-info/METADATA +47 -0
  31. microdf_python-0.4.5.dist-info/RECORD +35 -0
  32. {microdf_python-0.4.3.dist-info → microdf_python-0.4.5.dist-info}/WHEEL +1 -1
  33. microdf/chart_utils.py +0 -32
  34. microdf/charts.py +0 -56
  35. microdf/generic.py +0 -791
  36. microdf/style.py +0 -54
  37. microdf_python-0.4.3.dist-info/METADATA +0 -18
  38. microdf_python-0.4.3.dist-info/RECORD +0 -24
  39. {microdf_python-0.4.3.dist-info → microdf_python-0.4.5.dist-info/licenses}/LICENSE +0 -0
  40. {microdf_python-0.4.3.dist-info → microdf_python-0.4.5.dist-info}/top_level.txt +0 -0
microdf/__init__.py CHANGED
@@ -1,6 +1,4 @@
1
1
  from .agg import agg, combine_base_reform, pctchg_base_reform
2
- from .chart_utils import dollar_format, currency_format
3
- from .charts import quantile_pct_chg_plot
4
2
  from .concat import concat
5
3
  from .constants import (
6
4
  BENS,
@@ -32,21 +30,22 @@ from .inequality import (
32
30
  gini,
33
31
  t10_b50,
34
32
  top_0_1_pct_share,
35
- top_10_pct_share,
36
33
  top_1_pct_share,
34
+ top_10_pct_share,
37
35
  top_50_pct_share,
38
36
  top_x_pct_share,
39
37
  )
40
38
  from .io import read_stata_zip
39
+ from .microdataframe import MicroDataFrame, MicroDataFrameGroupBy
40
+ from .microseries import MicroSeries, MicroSeriesGroupBy
41
41
  from .poverty import (
42
- fpl,
43
- poverty_rate,
42
+ deep_poverty_gap,
44
43
  deep_poverty_rate,
44
+ fpl,
45
45
  poverty_gap,
46
+ poverty_rate,
46
47
  squared_poverty_gap,
47
- deep_poverty_gap,
48
48
  )
49
- from .style import AXIS_COLOR, DPI, GRID_COLOR, TITLE_COLOR, set_plot_style
50
49
  from .tax import mtr, tax_from_mtrs
51
50
  from .taxcalc import (
52
51
  add_weighted_metrics,
@@ -72,7 +71,6 @@ from .weighted import (
72
71
  weighted_quantile,
73
72
  weighted_sum,
74
73
  )
75
- from .generic import MicroDataFrame, MicroSeries
76
74
 
77
75
  name = "microdf"
78
76
  __version__ = "0.1.0"
@@ -82,11 +80,6 @@ __all__ = [
82
80
  "combine_base_reform",
83
81
  "pctchg_base_reform",
84
82
  "agg",
85
- # chart_utils.py
86
- "dollar_format",
87
- "currency_format",
88
- # charts.py
89
- "quantile_pct_chg_plot",
90
83
  # concat.py
91
84
  "concat",
92
85
  # constants.py
@@ -133,12 +126,6 @@ __all__ = [
133
126
  "poverty_gap",
134
127
  "squared_poverty_gap",
135
128
  "deep_poverty_gap",
136
- # style.py
137
- "AXIS_COLOR",
138
- "DPI",
139
- "GRID_COLOR",
140
- "TITLE_COLOR",
141
- "set_plot_style",
142
129
  # tax.py
143
130
  "mtr",
144
131
  "tax_from_mtrs",
@@ -164,7 +151,10 @@ __all__ = [
164
151
  "weighted_median",
165
152
  "add_weighted_quantiles",
166
153
  "quantile_chg",
167
- # generic.py
154
+ # microseries.py
168
155
  "MicroSeries",
156
+ "MicroSeriesGroupBy",
157
+ # microdataframe.py
169
158
  "MicroDataFrame",
159
+ "MicroDataFrameGroupBy",
170
160
  ]
microdf/_optional.py CHANGED
@@ -2,7 +2,7 @@ import distutils.version
2
2
  import importlib
3
3
  import types
4
4
  import warnings
5
-
5
+ from typing import Optional, Union
6
6
 
7
7
  # Adapted from:
8
8
  # https://github.com/pandas-dev/pandas/blob/master/pandas/compat/_optional.py
@@ -31,14 +31,13 @@ def _get_version(module: types.ModuleType) -> str:
31
31
 
32
32
  def import_optional_dependency(
33
33
  name: str,
34
- extra: str = "",
35
- raise_on_missing: bool = True,
36
- on_version: str = "raise",
37
- ):
38
- """Import an optional dependency.
39
- By default, if a dependency is missing an ImportError with a nice
40
- message will be raised. If a dependency is present, but too old,
41
- we raise.
34
+ extra: Optional[str] = "",
35
+ raise_on_missing: Optional[bool] = True,
36
+ on_version: Optional[str] = "raise",
37
+ ) -> Union[types.ModuleType, None]:
38
+ """Import an optional dependency. By default, if a dependency is missing an
39
+ ImportError with a nice message will be raised. If a dependency is present,
40
+ but too old, we raise.
42
41
 
43
42
  :param name: The module name. This should be top-level only, so that the
44
43
  version may be checked.
microdf/agg.py CHANGED
@@ -1,15 +1,16 @@
1
- import pandas as pd
2
1
  from typing import Optional
3
2
 
3
+ import pandas as pd
4
+
4
5
  import microdf as mdf
5
6
 
6
7
 
7
8
  def combine_base_reform(
8
9
  base: pd.DataFrame,
9
10
  reform: pd.DataFrame,
10
- base_cols: Optional[list],
11
- cols: Optional[list],
12
- reform_cols: Optional[list],
11
+ base_cols: Optional[list] = None,
12
+ cols: Optional[list] = None,
13
+ reform_cols: Optional[list] = None,
13
14
  ) -> pd.DataFrame:
14
15
  """Combine base and reform with certain columns.
15
16
 
@@ -25,7 +26,6 @@ def combine_base_reform(
25
26
  :type reform_cols: list, optional
26
27
  :returns: DataFrame with columns for base ("_base") and reform ("_reform").
27
28
  :rtype: pd.DataFrame
28
-
29
29
  """
30
30
  all_base_cols = mdf.listify([base_cols] + [cols])
31
31
  all_reform_cols = mdf.listify([reform_cols] + [cols])
@@ -35,17 +35,15 @@ def combine_base_reform(
35
35
 
36
36
 
37
37
  def pctchg_base_reform(combined: pd.DataFrame, metric: str) -> pd.Series:
38
- """Calculates the percentage change in a metric for a combined
39
- dataset.
38
+ """Calculates the percentage change in a metric for a combined dataset.
40
39
 
41
40
  :param combined: Combined DataFrame with _base and _reform columns.
42
41
  :type combined: pd.DataFrame
43
- :param metric: String of the column to calculate the difference.
44
- Must exist as metric_m_base and metric_m_reform in combined.
42
+ :param metric: String of the column to calculate the difference. Must exist
43
+ as metric_m_base and metric_m_reform in combined.
45
44
  :type metric: str
46
45
  :returns: Series with percentage change.
47
46
  :rtype: pd.Series
48
-
49
47
  """
50
48
  return combined[metric + "_m_reform"] / combined[metric + "_m_base"] - 1
51
49
 
@@ -55,8 +53,8 @@ def agg(
55
53
  reform: pd.DataFrame,
56
54
  groupby: str,
57
55
  metrics: list,
58
- base_metrics: Optional[list],
59
- reform_metrics: Optional[list],
56
+ base_metrics: Optional[list] = None,
57
+ reform_metrics: Optional[list] = None,
60
58
  ) -> pd.DataFrame:
61
59
  """Aggregates differences between base and reform.
62
60
 
@@ -67,8 +65,8 @@ def agg(
67
65
  :param groupby: Variable in base to group on.
68
66
  :type groupby: str
69
67
  :param metrics: List of variables to agg and calculate the % change of.
70
- These should have associated weighted columns ending in _m in base
71
- and reform.
68
+ These should have associated weighted columns ending in _m in base and
69
+ reform.
72
70
  :type metrics: list
73
71
  :param base_metrics: List of variables from base to sum.
74
72
  :type base_metrics: Optional[list]
@@ -76,7 +74,6 @@ def agg(
76
74
  :type reform_metrics: Optional[list]
77
75
  :returns: DataFrame with groupby and metrics, and _pctchg metrics.
78
76
  :rtype: pd.DataFrame
79
-
80
77
  """
81
78
  metrics = mdf.listify(metrics)
82
79
  metrics_m = [i + "_m" for i in metrics]
microdf/concat.py CHANGED
@@ -1,12 +1,15 @@
1
- import pandas as pd
2
1
  import inspect
2
+
3
+ import pandas as pd
4
+
3
5
  import microdf as mdf
6
+ from microdf.microdataframe import MicroDataFrame
4
7
 
5
8
 
6
- def concat(*args, **kwargs):
7
- """Concatenates MicroDataFrame objects, preserving weights.
8
- If concatenating horizontally, the first set of weights are used.
9
- All args and kwargs are passed to pd.concat.
9
+ def concat(*args, **kwargs) -> "MicroDataFrame":
10
+ """Concatenates MicroDataFrame objects, preserving weights. If
11
+ concatenating horizontally, the first set of weights are used. All args and
12
+ kwargs are passed to pd.concat.
10
13
 
11
14
  :return: MicroDataFrame with concatenated weights.
12
15
  :rtype: mdf.MicroDataFrame
microdf/custom_taxes.py CHANGED
@@ -1,13 +1,14 @@
1
- """
2
- Functions and data for estimating taxes outside the income tax system.
1
+ """Functions and data for estimating taxes outside the income tax system.
2
+
3
3
  Examples include value added tax, financial transaction tax, and carbon tax.
4
4
  """
5
5
 
6
- import microdf as mdf
6
+ from typing import Optional
7
7
 
8
8
  import numpy as np
9
9
  import pandas as pd
10
10
 
11
+ import microdf as mdf
11
12
 
12
13
  # Source:
13
14
  # https://www.taxpolicycenter.org/briefing-book/who-would-bear-burden-vat
@@ -35,24 +36,24 @@ FTT_INCIDENCE /= 100
35
36
 
36
37
 
37
38
  def add_custom_tax(
38
- df,
39
- segment_income,
40
- w,
41
- base_income,
42
- incidence,
43
- name,
44
- total=None,
45
- ratio=None,
46
- verbose=True,
47
- ):
39
+ df: pd.DataFrame,
40
+ segment_income: str,
41
+ w: str,
42
+ base_income: str,
43
+ incidence: pd.Series,
44
+ name: str,
45
+ total: Optional[float] = None,
46
+ ratio: Optional[float] = None,
47
+ verbose: Optional[bool] = True,
48
+ ) -> None:
48
49
  """Add a custom tax based on incidence analysis driven by percentiles.
49
50
 
50
51
  :param df: DataFrame.
51
52
  :param segment_income: Income measure used to segment tax units into
52
- quantiles.
53
+ quantiles.
53
54
  :param w: Weight used to segment into quantiles (either s006 or XTOT_m).
54
55
  :param base_income: Income measure by which incidence is multiplied to
55
- estimate liability.
56
+ estimate liability.
56
57
  :param incidence: pandas Series indexed on the floor of an income
57
58
  percentile, with values for the tax rate.
58
59
  :param name: Name of the column to add.
@@ -60,13 +61,12 @@ def add_custom_tax(
60
61
  liabilities are calculated only based on the incidence schedule.
61
62
  (Default value = None)
62
63
  :param ratio: Ratio to adjust the tax by, compared to the original tax.
63
- This acts as a multiplier for the incidence argument.
64
- (Default value = None)
64
+ This acts as a multiplier for the incidence argument. (Default value =
65
+ None)
65
66
  :param verbose: Whether to print the tax adjustment factor if needed.
66
67
  Defaults to True.
67
68
  :returns: Nothing. Adds the column name to df representing the tax
68
69
  liability. df is also sorted by segment_income.
69
-
70
70
  """
71
71
  if ratio is not None:
72
72
  incidence = incidence * ratio
@@ -95,14 +95,14 @@ def add_custom_tax(
95
95
 
96
96
 
97
97
  def add_vat(
98
- df,
99
- segment_income="tpc_eci",
100
- w="XTOT_m",
101
- base_income="aftertax_income",
102
- incidence=VAT_INCIDENCE,
103
- name="vat",
104
- **kwargs
105
- ):
98
+ df: pd.DataFrame,
99
+ segment_income: Optional[str] = "tpc_eci",
100
+ w: Optional[str] = "XTOT_m",
101
+ base_income: Optional[str] = "aftertax_income",
102
+ incidence: Optional[pd.Series] = VAT_INCIDENCE,
103
+ name: Optional[str] = "vat",
104
+ **kwargs,
105
+ ) -> None:
106
106
  """Add value added tax based on incidence estimate from Tax Policy Center.
107
107
 
108
108
  :param df: DataFrame with columns for tpc_eci, XTOT_m, and aftertax_income.
@@ -111,11 +111,9 @@ def add_vat(
111
111
  :param w: Default value = "XTOT_m")
112
112
  :param base_income: Default value = "aftertax_income")
113
113
  :param incidence: Default value = VAT_INCIDENCE)
114
- :param name: Default value = "vat")
115
- :param **kwargs: Other arguments passed to add_custom_tax().
116
- :returns: Nothing. Adds vat to df.
117
- df is also sorted by tpc_eci.
118
-
114
+ :param name: Default value = "vat") :param **kwargs: Other arguments passed
115
+ to add_custom_tax().
116
+ :returns: Nothing. Adds vat to df. df is also sorted by tpc_eci.
119
117
  """
120
118
  add_custom_tax(
121
119
  df, segment_income, w, base_income, incidence, name, **kwargs
@@ -123,14 +121,14 @@ def add_vat(
123
121
 
124
122
 
125
123
  def add_carbon_tax(
126
- df,
127
- segment_income="tpc_eci",
128
- w="XTOT_m",
129
- base_income="aftertax_income",
130
- incidence=CARBON_TAX_INCIDENCE,
131
- name="carbon_tax",
132
- **kwargs
133
- ):
124
+ df: pd.DataFrame,
125
+ segment_income: Optional[str] = "tpc_eci",
126
+ w: Optional[str] = "XTOT_m",
127
+ base_income: Optional[str] = "aftertax_income",
128
+ incidence: Optional[pd.Series] = CARBON_TAX_INCIDENCE,
129
+ name: Optional[str] = "carbon_tax",
130
+ **kwargs,
131
+ ) -> None:
134
132
  """Add carbon tax based on incidence estimate from the US Treasury
135
133
  Department.
136
134
 
@@ -140,11 +138,9 @@ def add_carbon_tax(
140
138
  :param w: Default value = "XTOT_m")
141
139
  :param base_income: Default value = "aftertax_income")
142
140
  :param incidence: Default value = CARBON_TAX_INCIDENCE)
143
- :param name: Default value = "carbon_tax")
144
- :param **kwargs: Other arguments passed to add_custom_tax().
145
- :returns: Nothing. Adds carbon_tax to df.
146
- df is also sorted by tpc_eci.
147
-
141
+ :param name: Default value = "carbon_tax") :param **kwargs: Other arguments
142
+ passed to add_custom_tax().
143
+ :returns: Nothing. Adds carbon_tax to df. df is also sorted by tpc_eci.
148
144
  """
149
145
  add_custom_tax(
150
146
  df, segment_income, w, base_income, incidence, name, **kwargs
@@ -152,14 +148,14 @@ def add_carbon_tax(
152
148
 
153
149
 
154
150
  def add_ftt(
155
- df,
156
- segment_income="tpc_eci",
157
- w="XTOT_m",
158
- base_income="aftertax_income",
159
- incidence=FTT_INCIDENCE,
160
- name="ftt",
161
- **kwargs
162
- ):
151
+ df: pd.DataFrame,
152
+ segment_income: Optional[str] = "tpc_eci",
153
+ w: Optional[str] = "XTOT_m",
154
+ base_income: Optional[str] = "aftertax_income",
155
+ incidence: Optional[pd.Series] = FTT_INCIDENCE,
156
+ name: Optional[str] = "ftt",
157
+ **kwargs,
158
+ ) -> None:
163
159
  """Add financial transaction tax based on incidence estimate from Tax
164
160
  Policy Center.
165
161
 
@@ -169,11 +165,9 @@ def add_ftt(
169
165
  :param w: Default value = "XTOT_m")
170
166
  :param base_income: Default value = "aftertax_income")
171
167
  :param incidence: Default value = FTT_INCIDENCE)
172
- :param name: Default value = "ftt")
173
- :param **kwargs: Other arguments passed to add_custom_tax().
174
- :returns: Nothing. Adds ftt to df.
175
- df is also sorted by tpc_eci.
176
-
168
+ :param name: Default value = "ftt") :param **kwargs: Other arguments passed
169
+ to add_custom_tax().
170
+ :returns: Nothing. Adds ftt to df. df is also sorted by tpc_eci.
177
171
  """
178
172
  add_custom_tax(
179
173
  df, segment_income, w, base_income, incidence, name, **kwargs
@@ -1,3 +1,5 @@
1
+ import pandas as pd
2
+
1
3
  import microdf as mdf
2
4
 
3
5
  # See
@@ -5,7 +7,7 @@ import microdf as mdf
5
7
  # for a comparison of income measures used here.
6
8
 
7
9
 
8
- def cash_income(df):
10
+ def cash_income(df: pd.DataFrame) -> pd.Series:
9
11
  """Calculates income after taxes and cash transfers.
10
12
 
11
13
  Defined as aftertax_income minus non-cash benefits.
@@ -22,7 +24,6 @@ def cash_income(df):
22
24
  * vet_ben
23
25
  * wic_ben
24
26
  :returns: A pandas Series with the cash income for each row in df.
25
-
26
27
  """
27
28
  return (
28
29
  df.aftertax_income
@@ -38,27 +39,25 @@ def cash_income(df):
38
39
  )
39
40
 
40
41
 
41
- def tpc_eci(df):
42
+ def tpc_eci(df: pd.DataFrame) -> pd.Series:
42
43
  """Approximates Tax Policy Center's Expanded Cash Income measure.
43
44
 
44
45
  Subtracts WIC, housing assistance, veteran's benefits, Medicare, and
45
- Medicaid from expanded_income. ECI adds income measures not modeled in
46
- Tax-Calculator, so these are ignored and will create a discrepancy
47
- compared to TPC's ECI.
46
+ Medicaid from expanded_income. ECI adds income measures not modeled in Tax-
47
+ Calculator, so these are ignored and will create a discrepancy compared to
48
+ TPC's ECI.
48
49
 
49
50
  :param df: DataFrame with columns from Tax-Calculator.
50
51
  :returns: pandas Series with TPC's ECI.
51
-
52
52
  """
53
53
  return df.expanded_income - df[mdf.ECI_REMOVE_COLS].sum(axis=1)
54
54
 
55
55
 
56
- def market_income(df):
57
- """Approximates CBO's market income concept, which is income
58
- before social insurance, means-tested transfers, and taxes.
56
+ def market_income(df: pd.DataFrame) -> pd.Series:
57
+ """Approximates CBO's market income concept, which is income before social
58
+ insurance, means-tested transfers, and taxes.
59
59
 
60
60
  :param df: DataFrame with expanded_income and benefits.
61
61
  :returns: pandas Series of the same length as df.
62
-
63
62
  """
64
63
  return df.expanded_income - df[mdf.BENS].sum(axis=1)
microdf/inequality.py CHANGED
@@ -1,9 +1,18 @@
1
+ from typing import List, Optional, Union
2
+
1
3
  import numpy as np
4
+ import pandas as pd
2
5
 
3
6
  import microdf as mdf
4
7
 
5
8
 
6
- def gini(df, col, w=None, negatives=None, groupby=None):
9
+ def gini(
10
+ df: pd.DataFrame,
11
+ col: str,
12
+ w: Optional[str] = None,
13
+ negatives: Optional[str] = None,
14
+ groupby: Optional[Union[str, List[str]]] = None,
15
+ ) -> float:
7
16
  """Calculates Gini index.
8
17
 
9
18
  :param df: DataFrame.
@@ -18,10 +27,14 @@ def gini(df, col, w=None, negatives=None, groupby=None):
18
27
  Defaults to None, which leaves negative values as they are.
19
28
  :param groupby: Column, or list of columns, to group by.
20
29
  :returns: A float, the Gini index.
21
-
22
30
  """
23
31
 
24
- def _gini(df, col, w=None, negatives=None):
32
+ def _gini(
33
+ df: pd.DataFrame,
34
+ col: str,
35
+ w: Optional[str] = None,
36
+ negatives: Optional[str] = None,
37
+ ) -> float:
25
38
  # Requires float numpy arrays (not pandas Series or lists) to work.
26
39
  x = np.array(df[col]).astype("float")
27
40
  if negatives == "zero":
@@ -50,7 +63,13 @@ def gini(df, col, w=None, negatives=None, groupby=None):
50
63
  return df.groupby(groupby).apply(lambda x: _gini(x, col, w, negatives))
51
64
 
52
65
 
53
- def top_x_pct_share(df, col, top_x_pct, w=None, groupby=None):
66
+ def top_x_pct_share(
67
+ df: pd.DataFrame,
68
+ col: str,
69
+ top_x_pct: float,
70
+ w: Optional[str] = None,
71
+ groupby: Optional[Union[str, List[str]]] = None,
72
+ ) -> float:
54
73
  """Calculates top x% share.
55
74
 
56
75
  :param df: DataFrame.
@@ -59,10 +78,11 @@ def top_x_pct_share(df, col, top_x_pct, w=None, groupby=None):
59
78
  :param w: Column representing weight in df.
60
79
  :param groupby: Column, or list of columns, to group by.
61
80
  :returns: The share of w-weighted val held by the top x%.
62
-
63
81
  """
64
82
 
65
- def _top_x_pct_share(df, col, top_x_pct, w=None):
83
+ def _top_x_pct_share(
84
+ df: pd.DataFrame, col: str, top_x_pct: float, w: Optional[str] = None
85
+ ) -> float:
66
86
  threshold = mdf.weighted_quantile(df, col, w, 1 - top_x_pct)
67
87
  top_x_pct_sum = mdf.weighted_sum(df[df[col] >= threshold], col, w)
68
88
  total_sum = mdf.weighted_sum(df, col, w)
@@ -75,7 +95,13 @@ def top_x_pct_share(df, col, top_x_pct, w=None, groupby=None):
75
95
  )
76
96
 
77
97
 
78
- def bottom_x_pct_share(df, col, bottom_x_pct, w=None, groupby=None):
98
+ def bottom_x_pct_share(
99
+ df: pd.DataFrame,
100
+ col: str,
101
+ bottom_x_pct: float,
102
+ w: Optional[str] = None,
103
+ groupby: Optional[Union[str, List[str]]] = None,
104
+ ) -> float:
79
105
  """Calculates bottom x% share.
80
106
 
81
107
  :param df: DataFrame.
@@ -84,12 +110,16 @@ def bottom_x_pct_share(df, col, bottom_x_pct, w=None, groupby=None):
84
110
  :param w: Column representing weight in df.
85
111
  :param groupby: Column, or list of columns, to group by.
86
112
  :returns: The share of w-weighted val held by the bottom x%.
87
-
88
113
  """
89
114
  return 1 - top_x_pct_share(df, col, 1 - bottom_x_pct, w, groupby)
90
115
 
91
116
 
92
- def bottom_50_pct_share(df, col, w=None, groupby=None):
117
+ def bottom_50_pct_share(
118
+ df: pd.DataFrame,
119
+ col: str,
120
+ w: Optional[str] = None,
121
+ groupby: Optional[Union[str, List[str]]] = None,
122
+ ) -> float:
93
123
  """Calculates bottom 50% share.
94
124
 
95
125
  :param df: DataFrame.
@@ -97,12 +127,16 @@ def bottom_50_pct_share(df, col, w=None, groupby=None):
97
127
  :param w: Column representing weight in df.
98
128
  :param groupby: Column, or list of columns, to group by.
99
129
  :returns: The share of w-weighted val held by the bottom 50%.
100
-
101
130
  """
102
131
  return bottom_x_pct_share(df, col, 0.5, w, groupby)
103
132
 
104
133
 
105
- def top_50_pct_share(df, col, w=None, groupby=None):
134
+ def top_50_pct_share(
135
+ df: pd.DataFrame,
136
+ col: str,
137
+ w: Optional[str] = None,
138
+ groupby: Optional[Union[str, List[str]]] = None,
139
+ ) -> float:
106
140
  """Calculates top 50% share.
107
141
 
108
142
  :param df: DataFrame.
@@ -110,12 +144,16 @@ def top_50_pct_share(df, col, w=None, groupby=None):
110
144
  :param w: Column representing weight in df.
111
145
  :param groupby: Column, or list of columns, to group by.
112
146
  :returns: The share of w-weighted val held by the top 50%.
113
-
114
147
  """
115
148
  return top_x_pct_share(df, col, 0.5, w, groupby)
116
149
 
117
150
 
118
- def top_10_pct_share(df, col, w=None, groupby=None):
151
+ def top_10_pct_share(
152
+ df: pd.DataFrame,
153
+ col: str,
154
+ w: Optional[str] = None,
155
+ groupby: Optional[Union[str, List[str]]] = None,
156
+ ) -> float:
119
157
  """Calculates top 10% share.
120
158
 
121
159
  :param df: DataFrame.
@@ -123,12 +161,16 @@ def top_10_pct_share(df, col, w=None, groupby=None):
123
161
  :param w: Column representing weight in df.
124
162
  :param groupby: Column, or list of columns, to group by.
125
163
  :returns: The share of w-weighted val held by the top 10%.
126
-
127
164
  """
128
165
  return top_x_pct_share(df, col, 0.1, w, groupby)
129
166
 
130
167
 
131
- def top_1_pct_share(df, col, w=None, groupby=None):
168
+ def top_1_pct_share(
169
+ df: pd.DataFrame,
170
+ col: str,
171
+ w: Optional[str] = None,
172
+ groupby: Optional[Union[str, List[str]]] = None,
173
+ ) -> float:
132
174
  """Calculates top 1% share.
133
175
 
134
176
  :param df: DataFrame.
@@ -136,12 +178,16 @@ def top_1_pct_share(df, col, w=None, groupby=None):
136
178
  :param w: Column representing weight in df.
137
179
  :param groupby: Column, or list of columns, to group by.
138
180
  :returns: The share of w-weighted val held by the top 1%.
139
-
140
181
  """
141
182
  return top_x_pct_share(df, col, 0.01, w, groupby)
142
183
 
143
184
 
144
- def top_0_1_pct_share(df, col, w=None, groupby=None):
185
+ def top_0_1_pct_share(
186
+ df: pd.DataFrame,
187
+ col: str,
188
+ w: Optional[str] = None,
189
+ groupby: Optional[Union[str, List[str]]] = None,
190
+ ) -> float:
145
191
  """Calculates top 0.1% share.
146
192
 
147
193
  :param df: DataFrame.
@@ -149,21 +195,24 @@ def top_0_1_pct_share(df, col, w=None, groupby=None):
149
195
  :param w: Column representing weight in df.
150
196
  :param groupby: Column, or list of columns, to group by.
151
197
  :returns: The share of w-weighted val held by the top 0.1%.
152
-
153
198
  """
154
199
  return top_x_pct_share(df, col, 0.001, w, groupby)
155
200
 
156
201
 
157
- def t10_b50(df, col, w=None, groupby=None):
202
+ def t10_b50(
203
+ df: pd.DataFrame,
204
+ col: str,
205
+ w: Optional[str] = None,
206
+ groupby: Optional[Union[str, List[str]]] = None,
207
+ ) -> float:
158
208
  """Calculates ratio between the top 10% and bottom 50% shares.
159
209
 
160
210
  :param df: DataFrame.
161
211
  :param col: Name of column in df representing value.
162
212
  :param w: Column representing weight in df.
163
213
  :param groupby: Column, or list of columns, to group by.
164
- :returns: The share of w-weighted val held by the top 10% divided by
165
- the share of w-weighted val held by the bottom 50%.
166
-
214
+ :returns: The share of w-weighted val held by the top 10% divided by the
215
+ share of w-weighted val held by the bottom 50%.
167
216
  """
168
217
  t10 = top_10_pct_share(df, col, w, groupby)
169
218
  b50 = bottom_50_pct_share(df, col, w, groupby)
microdf/io.py CHANGED
@@ -1,14 +1,14 @@
1
1
  import io
2
2
  import zipfile
3
- import requests
3
+
4
4
  import pandas as pd
5
+ import requests
5
6
 
6
7
  HEADER = {
7
- "User-Agent":
8
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) " +
9
- "AppleWebKit/537.36 (KHTML, like Gecko) " +
10
- "Chrome/50.0.2661.102 Safari/537.36"
11
- }
8
+ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) "
9
+ + "AppleWebKit/537.36 (KHTML, like Gecko) "
10
+ + "Chrome/50.0.2661.102 Safari/537.36"
11
+ }
12
12
 
13
13
 
14
14
  def read_stata_zip(url: str, **kwargs) -> pd.DataFrame:
@@ -19,11 +19,9 @@ def read_stata_zip(url: str, **kwargs) -> pd.DataFrame:
19
19
  Pending native support in
20
20
  https://github.com/pandas-dev/pandas/issues/26599.
21
21
 
22
- :param url: URL string of .zip file containing a single
23
- .dta file.
24
- :param **kwargs: Arguments passed to pandas.read_stata().
22
+ :param url: URL string of .zip file containing a single .dta file. :param
23
+ **kwargs: Arguments passed to pandas.read_stata().
25
24
  :returns: DataFrame.
26
-
27
25
  """
28
26
  r = requests.get(url, headers=HEADER)
29
27
  data = io.BytesIO(r.content)