Working with US Congress bill sponsorship data

Zachary Neal, Michigan State University, zpneal@msu.edu

Table of Contents

  1. Introduction
    1. Welcome
    2. The US legislative process
    3. Types and areas of bills
  2. Getting the data
  3. Constructing a network

Introduction (Neal 2022)

Welcome

This vignette briefly illustrates how to use the incidentally package to obtain data on bill sponsorship in US Congress, and how to use the backbone package to construct political networks from these data. For a more detailed tutorial, please see:

Neal, Z. P. (2022). Constructing legislative networks in R using incidentally and backbone. Connections. https://doi.org/10.2478/connections-2019.026

For a more general introduction to the incidentally package, see the main vignette. The incidentally package can be cited as:

Neal, Z. P. (2022). incidentally: An R package to generate incidence matrices and bipartite graphs. OSF Preprints. https://doi.org/10.31219/osf.io/ectms

If you have questions about the incidentally package or would like an incidentally hex sticker, please contact the maintainer Zachary Neal by email (zpneal@msu.edu) or via Mastodon (@zpneal@mastodon.social). Please report bugs in the backbone package at https://github.com/zpneal/incidentally/issues.

The US legislative process

In the US Congress, bills may become laws through a multi-step legislative process:

  1. A legislator in either the House of Represenatives or Senate introduces a bill for consideration. This individual is known as the bill’s sponsor. Additional legislators in the same chamber can express their support for the bill by joining as co-sponsors.
  2. The bill is debated, revised, and (possibly) voted on in the originating chamber.
  3. If the bill passes in the originating chamber, it is sent to the other chamber, where it is again debated, revised, and (possibly) voted on.
  4. If the bill passes in the second chamber, it is sent to the President. In some cases, bills are referred back to the originating chamber to reconcile differences in versions passed by each chamber.
  5. If the President signs the bill, it becomes law. If the President vetoes the bill, it is returned to the Congress, which can override the veto and make the bill a law with a two-thirds majority.

The vast majority of introduced bills are never formally voted on, and never become law, because they fail to pass one of these legislative hurdles. Therefore, focusing only on votes or passage provides limited information about legislators’ politcial positions. In contrast, because all introduced bills have sponsors and co-sponsors, legislators’ sponsorship behaviors provides rich data on their political positions.

Types and areas of bills

There are four types of legislation that can be introduced in the US Congress:

  1. Bills - This type is used for most legislation. If it passes both chambers of Congress and is signed by the President, it becomes a law. Bills introduced in the House are labeled H.R. and bills introduced in the Senate ate labeled S..
  2. Joint Resolutions - This type is nearly identical to a bill, except that it is also used when Congress proposes an amendment to the US Constitution. If it passes both chambers of Congress and is signed by the President, it becomes a law. Joint Resolutions introduced in the House are labeled H.J.Res. and bills introduced in the Senate ate labeled S.J.Res..
  3. Concurrent Resolutions - This type is used to make or amend procedural rules that apply to both chambers of Congress, and to express the sentiments of both chambers. They are not sent to the President and do not become law. Concurrent Resolutions introduced in the House are labeled H.Con.Res. and bills introduced in the Senate ate labeled S.Con.Res..
  4. Simple Resolutions - This type is used to make or amend procedural rules that apply to one chamber of Congress, and to express the sentiments of a single chamber (e.g., express condolences for the death of a member). They are not sent to the President and do not become law. Simple Resolutions introduced in the House are labeled H.Res. and bills introduced in the Senate ate labeled S.Res..

Because bills and joint resolutions can become laws, these often provide more information about legislators’ political positions than concurrent and simple resolutions, which are used only for procedural matters.

When any type of legislation is introduced, the Congressional Research Service assigns it to one of 32 broad policy areas. A complete list of policy areas and brief descriptions is available at https://www.congress.gov/help/field-values/policy-area.

back to Table of Contents

Getting the data

The incidence.from.congress() function in the incidentally package makes it easy to get data on legislators’ bill sponsorship activities. The incidentally package can be loaded in the usual way:

library(incidentally)
#> O  O  O  incidentally v1.0.2
#> |\ | /|  Cite: Neal, Z. P. (2022). incidentally: An R package for generating incidence matrices
#> |  |  |        and bipartite graphs. OSF Preprints. https://doi.org/10.31219/osf.io/ectms
#> |/ | \|  Help: type vignette("incidentally"); email zpneal@msu.edu; github zpneal/incidentally
#> X  X  X  Beta: type devtools::install_github("zpneal/incidentally", ref = "devel")

Upon successful loading, a startup message will display that shows the version number, citation, ways to get help, and ways to contact me.

Now we can use the incidence.from.congress() function to get data on legislators’ bill sponsorship activities:

I <- incidence.from.congress(session = 115, types = c("sres"), areas = c("All"), format = "data", narrative = TRUE)
#> Retriving bills from session 115
#> Examining 747 bills
#> 
#> === Suggested manuscript text and citations ===
#> We used the incidentally package for R (v1.0.2; Neal, 2022) to generate an incidence matrix recording Senators' bill sponsorships during the 115 session of the US Congress.
#> 
#> Neal, Z. P. 2022. Constructing legislative networks in R using incidentally and backbone. Connections, 42. https://doi.org/10.2478/connections-2019.026

In this example, we request data on Senate simple resolutions (types = c("sres")) in all policy areas (areas = "All")) that were introduced during the 115th session (session = 115), which took place between January 3, 2017 and January 3, 2019. Running this command can take some time because many bills must be downloaded and parsed, but a progress bar is displayed. By specifying narrative = TRUE, the function generates suggested text and citations for describing what it has done. By specifying format = "data", the resulting object I is a list containing (1) an incidence matrix recording which legislators sponsored or co-sponsored which bills, (2) a data frame of legislator characteristics, and (3) a data frame of bill characteristics:

I$matrix[1:5,1:5]
#>                                   SRES157 SRES158 SRES15 SRES162 SRES161
#> Sen. Cardin, Benjamin L. [D-MD]         1       1      0       0       0
#> Sen. McCain, John [R-AZ]                1       0      0       0       0
#> Sen. Markey, Edward J. [D-MA]           1       0      0       0       0
#> Sen. Coons, Christopher A. [D-DE]       1       0      0       1       0
#> Sen. Schatz, Brian [D-HI]               1       0      0       0       0
I$legislator[1:5,1:5]
#>        id                              name   last party state
#> 1 C000141   Sen. Cardin, Benjamin L. [D-MD] Cardin     D    MD
#> 2 M000303          Sen. McCain, John [R-AZ] Mccain     R    AZ
#> 3 M000133     Sen. Markey, Edward J. [D-MA] Markey     D    MA
#> 4 C001088 Sen. Coons, Christopher A. [D-DE]  Coons     D    DE
#> 5 S001194         Sen. Schatz, Brian [D-HI] Schatz     D    HI
I$bills[1:5,c(1,2,4,5)]
#>       bill introduced                               area sponsor.party
#> 1  SRES157 2017-05-04              international affairs             D
#> 8  SRES158 2017-05-04              international affairs             D
#> 22  SRES15 2017-01-20              international affairs             R
#> 33 SRES162 2017-05-11              international affairs             R
#> 43 SRES161 2017-05-10 armed forces and national security             D

Using the same parameters, but specifying format = "igraph" yields an igraph bipartite graph B that includes the legislator and bill characteristics as vertex attibutes:

B <- incidence.from.congress(session = 115, types = c("sres"), areas = c("All"), format = "igraph")
#> Retriving bills from session 115
#> Examining 747 bills
B
#> IGRAPH ff9cd1f UN-B 851 7909 -- 
#> + attr: name (v/c), type (v/l), party (v/c), state (v/c), last (v/c),
#> | id (v/c), introduced (v/c), title (v/c), area (v/c), sponsor.party
#> | (v/c), cosponsors.r (v/n), cosponsors.d (v/n), cosponsors.i (v/n),
#> | status (v/c)
#> + edges from ff9cd1f (vertex names):
#> [1] Sen. Cardin, Benjamin L. [D-MD]  --SRES157
#> [2] Sen. McCain, John [R-AZ]         --SRES157
#> [3] Sen. Markey, Edward J. [D-MA]    --SRES157
#> [4] Sen. Coons, Christopher A. [D-DE]--SRES157
#> [5] Sen. Schatz, Brian [D-HI]        --SRES157
#> + ... omitted several edges

back to Table of Contents

Constructing a network

The bill sponsorship data generated by incidence.from.congress() can be examined in a variety of ways. However, one common used of bill sponsorship data is the construction of a bill co-sponsorship network. In a bill co-sponsorship network, two legislators are connected if they sponsored or co-sponsored the same bills, which provides evidence of their political alignment and possibly that they are political allies. One key challenge in constructing co-sponsorship networks is deciding how many bills two legislators must (co-)sponsor together before inferring they are aligned or allies (Neal 2014, 2020). The backbone package offers several methods for making these inferences.

The backbone package can be loaded in the usual way:

library(backbone)
#>  ____   backbone v2.1.2
#> |  _ \  Cite: Neal, Z. P., (2022). Backbone: An R package to extract network backbones.
#> |#|_) |       PLOS ONE, 17, e0269137. https://doi.org/10.1371/journal.pone.0269137
#> |# _ <
#> |#|_) | Help: type vignette("backbone"); email zpneal@msu.edu; github zpneal/backbone
#> |____/  Beta: type devtools::install_github("zpneal/backbone", ref = "devel")

Upon successful loading, a startup message will display that shows the version number, citation, ways to get help, and ways to contact me.

Given the bipartite igraph object generated by incidence.from.congress() above, we can generate a political network among the Senators using:

network <- sdsm(B, alpha = 0.05, narrative = TRUE)
#> 
#> === Suggested manuscript text and citations ===
#> We used the backbone package for R (v2.1.2; Neal, 2022) to extract the unweighted backbone of the weighted projection of an unweighted bipartite network containing 104 agents and 747 artifacts. An edge was retained in the backbone if its weight was statistically significant (alpha = 0.05) using the stochastic degree sequence model (SDSM; Neal, 2014). This reduced the number of edges by 89.5%, and reduced the number of connected nodes by 4.8%.
#> 
#> Neal, Z. P. 2022. backbone: An R Package to Extract Network Backbones. PLOS ONE, 17, e0269137. https://doi.org/10.1371/journal.pone.0269137
#> 
#> Neal, Z. P. (2014). The backbone of bipartite projections: Inferring relationships from co-authorship, co-sponsorship, co-attendance and other co-behaviors. Social Networks, 39, 84-97. https://doi.org/10.1016/j.socnet.2014.06.001
network
#> IGRAPH 1ab2123 UNW- 104 560 -- 
#> + attr: name (v/c), party (v/c), state (v/c), last (v/c), id (v/c),
#> | weight (e/n), sign (e/n)
#> + edges from 1ab2123 (vertex names):
#> [1] Sen. Cardin, Benjamin L. [D-MD]--Sen. Markey, Edward J. [D-MA]    
#> [2] Sen. Cardin, Benjamin L. [D-MD]--Sen. Coons, Christopher A. [D-DE]
#> [3] Sen. Cardin, Benjamin L. [D-MD]--Sen. Menendez, Robert [D-NJ]     
#> [4] Sen. Cardin, Benjamin L. [D-MD]--Sen. Van Hollen, Chris [D-MD]    
#> [5] Sen. Cardin, Benjamin L. [D-MD]--Sen. Booker, Cory A. [D-NJ]      
#> [6] Sen. Cardin, Benjamin L. [D-MD]--Sen. Whitehouse, Sheldon [D-RI]  
#> [7] Sen. McCain, John [R-AZ]       --Sen. Rubio, Marco [R-FL]         
#> + ... omitted several edges

The stochastic degree sequence model (SDSM) connects two legislators if they (co-)sponsored statistically significantly (at the alpha = 0.05 level) more bills together than would be expected if (a) their total number of sponsorships was approximately the same and (b) each bill’s total number of sponsorships was approximately the same, but (c) they randomly chose which bills to sponsor. Because we started with an igraph object B, the result is also an igraph object network that contains the Senators’ characteristics as vertex attributes. By specifying narrative = TRUE, the function generates suggested text and citations for describing what it has done.

We can use the igraph package to plot this network, coloring each node by political party:

V(network)$color <- rgb(1,0,0,.5)  #Define the color of Republicans
V(network)$color[which(V(network)$party=="D")] <- rgb(0,0,1,.5)  #...of Democrats
V(network)$color[which(V(network)$party=="I")] <- rgb(0,1,0,.5)  #...of Independents
plot(network, vertex.label = NA, vertex.color = V(network)$color, vertex.frame.color = NA, vertex.size = 10)

This network clearly shows the partisan structure of the US Senate: Democrats (blue) mostly work with other Democrats, and Republicans (red) mostly work with other Republicans.

We can also generate a signed political network:

signed <- sdsm(B, alpha = 0.05, signed = TRUE)

where Senators that sponsor significantly many bills are connected by a positive tie that might indicate alliance, while Senators that sponsor significantly few bills are connected by a negative tie that might indicate opposition.

Again, using the igraph package to plot this network:

V(signed)$color <- rgb(1,0,0,.5)  #Define the color of Republicans
V(signed)$color[which(V(signed)$party=="D")] <- rgb(0,0,1,.5)  #...of Democrats
V(signed)$color[which(V(signed)$party=="I")] <- rgb(0,1,0,.5)  #...of Independents
E(signed)$color <- rgb(0,1,0,1)  #Define color of positive edges
E(signed)$color[which(E(signed)$weight==-1)] <- rgb(1,0,0,.01)  #Define color of negative edges
layout <- layout_nicely(delete_edges(signed, which(E(signed)$weight==-1)))  #Get layout based on positive edges
plot(signed, vertex.label = NA, vertex.color = V(signed)$color, vertex.frame.color = NA, vertex.size = 10, layout = layout)

This network still shows the partisan structure of the US Senate, but illustrates that there are positive ties within-party and negative ties between-party.

back to Table of Contents

References

Neal, Zachary P. 2014. “The Backbone of Bipartite Projections: Inferring Relationships from Co-Authorship, Co-Sponsorship, Co-Attendance and Other Co-Behaviors.” Social Networks 39 (October): 84–97. https://doi.org/10.1016/j.socnet.2014.06.001.
———. 2020. “A Sign of the Times? Weak and Strong Polarization in the US Congress, 1973–2016.” Social Networks 60: 103–12. https://doi.org/10.1016/j.socnet.2018.07.007.
———. 2022. “Constructing Legislative Networks in r Using Incidentally and Backbone.” Connections 42. https://doi.org/10.2478/connections-2019.026.