How disabilities affect Black employment¶
How does prime-age employment (the employment rate of civilians aged 25 to 54) vary with race and disability status? How does disability status vary by race? How do race and disability status compare in predicting employment? In this post, I use the monthly Current Population Survey from January 2018 to May 2020 to find out.
I find that the disability employment gap is 45 percentage points, with and without controlling for factors like age. The racial employment gap (non-Black minus Black) is about 4 points, but since Black people are more likely to have a disability—specifically physical and mobility limitations that most severely reduce employment—this gap shrinks to 2.9 points when controlling for disabilities. While most individual disabilities do not have a differential impact on Blacks, having any disability reduces Black employment 3 points more than non-Black employment.
Background¶
The prime-age employment rate (often abbreviated as PAEPOP, for Prime Age Employment POPulation ratio) is used as a consistent measure of employment trends by economists who want to avoid relying on whether survey respondents say they’re still looking for work. The calculation is simply the share of civilians aged 25 to 54 that reported working in the survey week.
Federal Reserve Economic Data publishes some related trends, e.g. PAEPOP by disability and gender and black employment rate among the aged 16+ population, but we need to limit by ages to avoid effects of college education and early retirement, both of which may reflect lower employment without worse labor market outcomes. For the right statistics, we need to go to the CPS microdata instead (I used IPUMS to extract it).
For simplicity, I focus on two binary features identified in the CPS: being Black only (compared to all other races), and reporting any physical or cognitive difficulty (which I describe here as having a disability).
Employment trends¶
The employment gap between people with and without disabilities has been roughly 45 percentage points since 2018.
### LOAD PACKAGES ###
import pandas as pd
import numpy as np
import microdf as mdf
import plotly.express as px
import statsmodels.api as sm
import stargazer.stargazer as sg
### SETTINGS ###
# Colors from https://material.io/design/color/the-color-system.html
BLUE = '#1976D2'
GRAY = '#BDBDBD'
RED = '#C62828'
PURPLE = '#6A1B9A'
LIGHT_BLUE = '#64B5F6'
PINK = '#EF9A9A'
COLOR_MAP = {
'Black': BLUE,
'Not Black': GRAY,
'Has disability': RED,
'No disability': GRAY,
'Black, Has disability': PURPLE,
'Black, No disability': LIGHT_BLUE,
'Not Black, Has disability': PINK,
'Not Black, No disability': GRAY
}
### LOAD DATA ###
# CPS data extracted from IPUMS.
cps = pd.read_csv('cps.csv.gz')
### PREPROCESS ###
# cps = cps_raw.copy(deep=True)
cps.columns = cps.columns.str.lower()
cps.rename({'wtfinl': 'w'}, axis=1, inplace=True)
cps['day'] = 12 # CPS asks about week including 12th of the month.
cps['date'] = pd.to_datetime(cps[['year', 'month', 'day']])
# May be unnecessary.
cps = cps[cps.date > pd.to_datetime('2017-12-31')]
# Create descriptive bools from codes.
cps['female'] = np.where(cps.sex == 2, 1, 0)
# Multiply by 100 for charts and easier regression interpretation.
cps['emp'] = 100 * cps.empstat.isin([10, 12])
cps['black'] = np.where(cps.race == 200, 'Black', 'Not Black')
# Recode disability into True/False/None.
DIFFS = ['diffhear', 'diffeye', 'diffrem', 'diffphys', 'diffmob', 'diffcare']
for i in DIFFS + ['diffany']:
cps[i] = np.where(cps[i] == 0, np.nan, cps[i] == 2)
# Limit to prime-age civilians and relevant columns.
cps = cps[(cps.empstat != 1) # Not in armed forces.
& cps.age.between(25, 54)]
assert cps.diffany.isna().sum() == 0
cps['disability'] = np.where(cps.diffany == 1, 'Has disability',
'No disability')
# Add time fixed effects for regression.
cps['month_fe'] = ('t' + cps.year.astype(str) +
cps.month.astype(str).str.zfill(2))
cps = pd.concat([cps, pd.get_dummies(cps.month_fe, drop_first=True)], axis=1)
# Get list of month FEs for regressions later.
month_fes = cps.month_fe.unique()[1:].tolist()
# No longer need other time columns.
cps.drop(['year', 'month', 'day', 'month_fe'], axis=1, inplace=True)
# Dummy for Covid-19, which came into full effects in the April 2020 survey.
cps['covid'] = np.where(cps.date > '2020-04-01', 1, 0)
# Add other features for regression.
cps['age2'] = np.power(cps.age, 2)
cps['const'] = 1
# Count difficulties.
cps['num_diffs'] = cps[DIFFS].sum(axis=1)
# Group-specific time trends, in days.
def time_trend(condition):
return np.where(condition,
(cps.date - pd.to_datetime('2000-01-01')).dt.days, 0)
cps['date_black'] = time_trend(cps.black == 'Black')
cps['date_disability'] = time_trend(cps.disability == 'Has disability')
cps['date_black_disability'] = time_trend(
(cps.black == 'Black') & (cps.disability == 'Has disability'))
### ANALYSIS ###
# Create grouped dataframe.
grouped = cps.groupby(['date', 'black', 'disability', 'emp'])[['w']].sum()
grouped.reset_index(inplace=True)
# Add conditional columns for creating rates.
mdf.add_weighted_metrics(grouped, ['emp'], 'w')
grouped['disability_m'] = np.where(grouped.disability == 'Has disability',
grouped.w_m, 0)
def add_emp_rate(df):
df['emp'] = df.emp_m / df.w_m
df['emp_round'] = df.emp.round(1)
df.drop(['emp_m', 'w_m'], axis=1, inplace=True)
df.reset_index(inplace=True)
def add_disability_rate(df):
df['disability_rate'] = 100 * df.disability_m / df.w_m
df['disability_rate_round'] = df.disability_rate.round(1)
df.drop(['disability_m', 'w_m'], axis=1, inplace=True)
df.reset_index(inplace=True)
race_emp = grouped.groupby(['date', 'black'])[['emp_m', 'w_m']].sum()
add_emp_rate(race_emp)
disability_emp = grouped.groupby(['date', 'disability'])[
['emp_m', 'w_m']].sum()
add_emp_rate(disability_emp)
race_disability = grouped.groupby(['date', 'black'])[
['disability_m', 'w_m']].sum()
add_disability_rate(race_disability)
race_disability_emp = grouped.groupby(['date', 'black', 'disability'])[
['emp_m', 'w_m']].sum()
add_emp_rate(race_disability_emp)
race_disability_emp['label'] = (race_disability_emp.black + ', ' +
race_disability_emp.disability)
### VISUALIZATION ###
def line_graph(df, x, y, color, title, yaxis_title):
fig = px.line(df, x=x, y=y, color=color, color_discrete_map=COLOR_MAP)
fig.update_layout(
title=title,
xaxis_title='',
yaxis_title=yaxis_title,
yaxis_ticksuffix='%',
legend_title_text='',
font=dict(family='Roboto'),
hovermode='x',
plot_bgcolor='white'
)
fig.update_traces(mode='markers+lines', hovertemplate=None)
fig.show()
# Plot by disability status.
line_graph(disability_emp, x='date', y='emp_round', color='disability',
title='Prime-age employment rate by disability status',
yaxis_title='Employment rate of civilians aged 25 to 54')