held-for-study

Created by: SmirkyGraphs. Code: Github. Source: RI Legislature Site.


Held for Further Study: Where Bills Go to Die

Bills in Rhode Island face a big hurdle, making it out of committee and not being "Held for Further Study". Once a bill is introduced and sent to committee, the first vote it recieves is whether or not it should be "Held for Further Study". A bill held for further study is indefinitely postpone, however can be considered again by the committee. Despite the naming, no study actually takes place, and if reintroduced, no study is prestended.

This notebook will take a look at how many bills end up "held for further study" and which chamber they were started in from 2007-2019.


In [1]:
import pandas as pd
import numpy as np
In [2]:
df = pd.read_csv('./data/clean/bill_actions.csv')

# removes resolutions
df = df[~df['bill_id'].str.contains('R')]

# remove duplicate (created when splitting action_type)
df = df.drop_duplicates(subset=(['action', 'lookup_id']))

# adding action_num increments of bill
df['action_num'] = df.groupby('lookup_id').cumcount()
In [3]:
# total bills introduced
total_bills = df['lookup_id'].nunique()

# total bills ever "held for further study"
held_for_study = df[df['type'] == 'held for further study']['lookup_id'].unique().tolist()

# total bills that never left "held for further study"
last_action = df.groupby('lookup_id')['type'].agg('last').reset_index()
last_action = last_action[last_action['type'] == 'held for further study']
died_in_study = last_action['lookup_id'].unique().tolist()

# final calcs

total_held_for_study = int(round(len(held_for_study)/total_bills, 2) * 100)
total_died_held = int(round(len(died_in_study)/len(held_for_study), 2) * 100)

print(f'total held for study: {total_held_for_study}% ({len(held_for_study)})')
print(f'total died held for study: {total_died_held}% ({len(died_in_study)})')
total held for study: 64% (16509)
total died held for study: 63% (10473)

Bills Held & Died for Further Study by Year (Percents Compared to Total Bills)

In [4]:
df.loc[df['lookup_id'].isin(died_in_study), 'ended_held_for_study'] = True
df.loc[df['lookup_id'].isin(held_for_study), 'ever_held_for_study'] = True

held = df.drop_duplicates('lookup_id')
held = held.groupby('session')['lookup_id', 'ever_held_for_study', 'ended_held_for_study'].count()

held['percent_ever_held'] = (round(held['ever_held_for_study']/held['lookup_id'], 2)*100).astype(int).astype(str) + '%'
held['percent_ended_held'] = (round(held['ended_held_for_study']/held['lookup_id'], 2)*100).astype(int).astype(str) + '%'

held['x'] = (round(held['ended_held_for_study']/held['ever_held_for_study'], 2)*100).astype(int).astype(str) + '%'

held.columns = ['count_total', 'count_ever_held', 'count_died_held', 
                '(% total)_ever_held', '(% total)_died_held', '(% held)_died_held']

cols = ['count_total','count_ever_held','(% total)_ever_held','count_died_held','(% total)_died_held', '(% held)_died_held']
held = held.reindex(columns=cols)
held
Out[4]:
count_total count_ever_held (% total)_ever_held count_died_held (% total)_died_held (% held)_died_held
session
2007 2255 1275 56% 809 36% 63%
2008 2159 1201 56% 779 36% 65%
2009 1999 1124 56% 740 37% 66%
2010 1861 910 49% 618 33% 68%
2011 1926 1173 61% 767 40% 65%
2012 1908 1043 55% 651 34% 62%
2013 1907 1234 65% 708 37% 56%
2014 2036 1298 64% 772 38% 59%
2015 1896 1305 69% 835 44% 64%
2016 2068 1473 71% 911 44% 62%
2017 1963 1555 79% 961 49% 62%
2018 1935 1473 76% 978 51% 66%
2019 1788 1445 81% 944 53% 65%

Bills Held & Died for Further Study by Year (Seperated by Chamber)

In [5]:
chamber = df.drop_duplicates('lookup_id').copy()

chamber.loc[chamber['bill_id'].str.contains('H'), 'chamber_origin'] = 'house'
chamber.loc[chamber['bill_id'].str.contains('S'), 'chamber_origin'] = 'senate'

held = chamber.groupby(['chamber_origin', 'session'])['lookup_id', 'ever_held_for_study', 'ended_held_for_study'].count()
held['percent_ever_held'] = (round(held['ever_held_for_study']/held['lookup_id'], 2)*100).astype(int).astype(str) + '%'
held['percent_ended_held'] = (round(held['ended_held_for_study']/held['lookup_id'], 2)*100).astype(int).astype(str) + '%'

held['x'] = (round(held['ended_held_for_study']/held['ever_held_for_study'], 2)*100).astype(int).astype(str) + '%'

held.columns = ['count_total', 'count_ever_held', 'count_died_held', 
                '(% total)_ever_held', '(% total)_died_held', '(% held)_died_held']

cols = ['count_total','count_ever_held','(% total)_ever_held','count_died_held','(% total)_died_held', '(% held)_died_held']
held = held.reindex(columns=cols)
held
Out[5]:
count_total count_ever_held (% total)_ever_held count_died_held (% total)_died_held (% held)_died_held
chamber_origin session
house 2007 1279 813 64% 519 41% 64%
2008 1184 737 62% 502 42% 68%
2009 1114 732 66% 485 44% 66%
2010 1037 620 60% 458 44% 74%
2011 1048 756 72% 528 50% 70%
2012 1045 637 61% 422 40% 66%
2013 1076 757 70% 460 43% 61%
2014 1126 815 72% 526 47% 65%
2015 1072 814 76% 556 52% 68%
2016 1140 906 79% 589 52% 65%
2017 1119 953 85% 624 56% 65%
2018 1112 913 82% 625 56% 68%
2019 973 826 85% 593 61% 72%
senate 2007 976 462 47% 290 30% 63%
2008 975 464 48% 277 28% 60%
2009 885 392 44% 255 28% 65%
2010 824 290 35% 160 19% 55%
2011 878 417 47% 239 27% 56%
2012 863 406 47% 229 27% 56%
2013 831 477 56% 248 30% 52%
2014 910 483 53% 246 27% 51%
2015 824 491 60% 279 34% 56%
2016 928 567 61% 322 35% 56%
2017 844 602 71% 337 40% 56%
2018 823 560 68% 353 43% 63%
2019 815 619 76% 351 43% 56%

Making Extract of Bills Held for Study

In [6]:
df = pd.read_csv('./data/clean/bill_actions.csv')

# removes resolutions
df = df[~df['bill_id'].str.contains('R')]

# remove duplicate (created when splitting action_type)
df = df.drop_duplicates(subset=(['action', 'lookup_id']))

# adding action_num increments of bill
df['action_num'] = df.groupby('lookup_id').cumcount()
In [7]:
# creating dataset for held for study tableau sheet
df.loc[df['lookup_id'].isin(died_in_study), 'ended_held_for_study'] = True
df.loc[df['lookup_id'].isin(held_for_study), 'ever_held_for_study'] = True

df = df.fillna(False)

committee = df.groupby('lookup_id')['action'].agg(['first']).reset_index()
committee['first'] = committee['first'].apply(lambda x: x.split(', ')[-1])
committee = committee.rename(columns={'first':'committee'})


df = df.merge(committee, on='lookup_id')
In [8]:
df.to_csv('./data/clean/held_for_study.csv', index=False)