{"id":13513,"date":"2026-01-12T11:21:19","date_gmt":"2026-01-12T16:21:19","guid":{"rendered":"https:\/\/blogs.mathworks.com\/cleve\/?p=13513"},"modified":"2026-01-13T14:18:27","modified_gmt":"2026-01-13T19:18:27","slug":"svd-measures-partisanship-in-the-u-s-senate","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/cleve\/2026\/01\/12\/svd-measures-partisanship-in-the-u-s-senate\/","title":{"rendered":"SVD Measures Partisanship  in the U. S. Senate"},"content":{"rendered":"<div class=\"content\"><!--introduction-->\r\n<p>My first blog about SVD and Partisanship in the U. S. Senate was <a href=\"https:\/\/blogs.mathworks.com\/cleve\/2020\/08\/23\/svd-quantifies-increasing-partisanship-in-the-u-s-senate\/\">five years ago<\/a>. Today's post updates that to 2025.<\/p>\r\n<!--\/introduction-->\r\n<h3>Contents<\/h3>\r\n<div>\r\n<ul>\r\n<li>\r\n<a href=\"#96185607-ec53-489b-a67a-8411f707be80\">SVD Measures Partisanship<\/a>\r\n<\/li>\r\n<li>\r\n<a href=\"#2f5e01d4-f465-45ed-89d7-3bdb991bcf37\">The Senate<\/a>\r\n<\/li>\r\n<li>\r\n<a href=\"#1cc976e3-58fb-4d25-a8ea-0dc5fb83d624\">The Data<\/a>\r\n<\/li>\r\n<li>\r\n<a href=\"#79e14eb8-1749-4ab9-a327-be5284aa1d95\">The Matrices<\/a>\r\n<\/li>\r\n<li>\r\n<a href=\"#dbd932a4-edd0-4ba6-98b4-db3b5db53f4d\">Partisanship<\/a>\r\n<\/li>\r\n<li>\r\n<a href=\"#2ce19fea-83e0-4826-996b-09dc51a3bf25\">Compare<\/a>\r\n<\/li>\r\n<li>\r\n<a href=\"#8c3674d4-e24d-4dc7-bcc3-485585eadef5\">Increasing Partisanship<\/a>\r\n<\/li>\r\n<\/ul>\r\n<\/div>\r\n<h4>SVD Measures Partisanship<a name=\"96185607-ec53-489b-a67a-8411f707be80\"><\/a>\r\n<\/h4>\r\n<p>Many observers have noted that the United States Senate has become increasingly partisan in recent years. Votes are being made more frequently along strict political party lines. The singular value decomposition, the SVD, of matrices derived from records of roll call votes in the senate can measure this partisanship.<\/p>\r\n<h4>The Senate<a name=\"2f5e01d4-f465-45ed-89d7-3bdb991bcf37\"><\/a>\r\n<\/h4>\r\n<p>Senators serve six-year terms and every two years about one-third of the senate stands for reelection or new senators are elected. So, a new \"Congress\" convenes every two years and has two year-long \"Sessions\". The first session was in 1789. The 101-st Congress began in 1989 and last year, 2025, is the First Session of the 119-th Congress.<\/p>\r\n<p>\r\n<img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/cleve\/files\/division2025.png\" alt=\"\"> <\/p>\r\n<p>This bar chart shows the division between the Republican and Democratic parties over our time period. The data from the web site <a href=\"https:\/\/www.senate.gov\/history\/partydiv.htm\" target=\"_blank\" rel=\"noopener\">party division<\/a> comes with the caveat, \"The actual number of senators representing a particular party often changes during a Congress, due to the death or resignation of a senator, or as a consequence of a member changing parties.\"<\/p>\r\n<h4>The Data<a name=\"1cc976e3-58fb-4d25-a8ea-0dc5fb83d624\"><\/a>\r\n<\/h4>\r\n<p>The web site <a href=\"https:\/\/www.senate.gov\" target=\"_blank\" rel=\"noopener\">www.senate.gov<\/a> has year-by-year records of voting in the senate. We are going to look at 37 years, from 1989 to 2025. For example, the URL<\/p>\r\n<p>\r\n<a href=\"https:\/\/www.senate.gov\/legislative\/LIS\/roll_call_votes\/vote1162\/vote_116_2_00033.xml\" target=\"_blank\" rel=\"noopener\">https: \/\/www.senate.gov\/legislative\/LIS\/roll_call_votes\/vote1162\/vote_116_2_00033.xml<\/a>\r\n<\/p>\r\n<p>points to the record of a roll call vote taken in the senate early in 2020. The congress number, 116, and the session, 2, each appear twice. The 33 signifies this is the 33rd vote of this session.<\/p>\r\n<p>Each roll-call vote is recorded in an XML file. XML is the abbreviation for eXtensible Markup Language, an important standard from the WWW Consortium defining a format for encoding documents that is both human and machine readable. I was pleased to find MATLAB Central File Exchange <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/28518-xml2struct\">28518-xml2struct<\/a> by Wouter Falkena. As the function name implies, this handy code \"converts an XML file into a MATLAB structure for easy access to the data.\"<\/p>\r\n<p>You can also use your browser to access the example URL and (a) examine the XML, and (b) see why bills 33 and 34 from year 2020 are not typical measures before the Senate.<\/p>\r\n<h4>The Matrices<a name=\"79e14eb8-1749-4ab9-a327-be5284aa1d95\"><\/a>\r\n<\/h4>\r\n<p>Once you find your way through the layers of structure that results from the XML, you will have many details about each senate roll call vote. In particular, for each senator who voted, you will have a structure with fields full name, last name, first name, party, state, vote, and member id.<\/p>\r\n<p>For each year, we create a matrix of +1s, -1s, and 0s. A +1 is for a vote of \"Yea\" or \"Guilty\", a -1 is a \"Nay\" or \"Not Guilty\", and a 0 is for anything else, which includes \"Not Voting\", \"Present\" (abstain), and something too complicated to explain called \"Present, Giving Live Pair\". Because there are 100 senators, the matrix has 100 rows. The number of columns is the number of roll call votes taken that year. The matrices range in size from 100-by-163 for 2016 to 100-by-613 for 1995.<\/p>\r\n<p>The XML is organized using last names of senators in alphabetic order -- Alexander (R-TN), Baldwin (D-WI), Barrasso (R-WY), ..., Young(R-IN). At first, I tried to create matrices with rows in this order. But senators retire or die in midsession, so this ordering proved to be difficult to manage correctly. Ultimately, I decided to order the rows by states. Each state is allocated two rows; the name of the specific senator occupying each row is irrelevant. After the matrix for a given year is complete, I reorder the rows so that all the senators from each party are grouped together. The one or two senators who declare themselves to be independent (but who caucus with a major party) are between the two parties.<\/p>\r\n<p>Here are the matrices, 37 of them, one for each session from 1989 to 2025. A good way to see the structure of these matrices is to view them as images. Red is \"Yea\" or \"Guilty\", gold is \"Nay\" or \"Not Guilty\", and white is not present, abstain or other.<\/p>\r\n<p>\r\n<img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/cleve\/files\/senate_gif1.gif\" alt=\"\"> <\/p>\r\n<h4>Partisanship<a name=\"dbd932a4-edd0-4ba6-98b4-db3b5db53f4d\"><\/a>\r\n<\/h4>\r\n<p>The SVD of these matrices provides the basis for our analysis. The singular values decrease very rapidly with increasing index, so the matrices can be well approximated by matrices of rank two. When viewed from the record of roll call votes, the U. S. Senate is nearly two-dimensional.<\/p>\r\n<p>Let <tt>A(y)<\/tt> be the matrix of 1s, -1s and 0s summarizing the roll call votes in year <tt>y<\/tt>. Let<\/p>\r\n<pre class=\"language-matlab\">sigma=svd(A(y))\r\n<\/pre>\r\n<p>Then the <i>partisanship<\/i> for year <tt>y<\/tt> is defined usinng the third singular value.<\/p>\r\n<pre class=\"language-matlab\">partianship=1-sigma(3)\/sigma(1)\r\n<\/pre>\r\n<p>This quantity measures how close the voting pattern is to being two-dimensional.<\/p>\r\n<h4>Compare<a name=\"2ce19fea-83e0-4826-996b-09dc51a3bf25\"><\/a>\r\n<\/h4>\r\n<p>For example, 1991 is one of the least partisan years in our sample, and 2025 is one of the most partisan years. You can immediately see that 2025 has much less detailed structure than 1991; it is closer to being two-dimensional<\/p>\r\n<p>\r\n<img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/cleve\/files\/A1991a.png\" alt=\"\"> <\/p>\r\n<p>\r\n<img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/cleve\/files\/A2025.png\" alt=\"\"> <\/p>\r\n<h4>Increasing Partisanship<a name=\"8c3674d4-e24d-4dc7-bcc3-485585eadef5\"><\/a>\r\n<\/h4>\r\n<p>This animation shows the distribution of the first ten singular values for the years from 1989 to 2025. The singular values are normalized so that <tt>1-sigma(1) = 0<\/tt>. Then the third singular value is highlighted.<\/p>\r\n<p>\r\n<img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/cleve\/files\/senate_gif2.gif\" alt=\"\"> <\/p>\r\n<p>Finally, here is this measure of partisanship for each year from 1989 to 2025, and a linear least squares fit. With this much scatter is the values, the exact fit can't be taken too seriously. But there is definitely an upward trend. Partisanship in the U. S. Senate has increased from less than 70% thirty years ago to more than 80% today.<\/p>\r\n<p>\r\n<img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/cleve\/files\/partisanship_a.png\" alt=\"\"> <\/p>\r\n<script language=\"JavaScript\"> <!-- \r\n    function grabCode_581e808db466464aa3eed7e7508fa69e() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='581e808db466464aa3eed7e7508fa69e ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 581e808db466464aa3eed7e7508fa69e';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2026 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script>\r\n<p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\">\r\n<br>\r\n<a href=\"javascript:grabCode_581e808db466464aa3eed7e7508fa69e()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript>\r\n<\/span><\/a>\r\n<br>\r\n<br>\r\n      Published with MATLAB&reg; R2024b<br>\r\n<\/p>\r\n<\/div>\r\n<!--\r\n581e808db466464aa3eed7e7508fa69e ##### SOURCE BEGIN #####\r\n%% SVD Measures Partisanship  in the U. S. Senate\r\n% My first blog about SVD and Partisanship in the U. S. Senate was\r\n% <https:\/\/blogs.mathworks.com\/cleve\/2020\/08\/23\/svd-quantifies-increasing-partisanship-in-the-u-s-senate\/\r\n% five years ago>.  Today's post updates that to 2025.\r\n\r\n%% SVD Measures Partisanship \r\n% Many observers have noted that the United States Senate has become\r\n% increasingly partisan in recent years.  Votes are being made more\r\n% frequently along strict political party lines.  The singular value \r\n% decomposition, the SVD, of matrices derived from records of roll call\r\n% votes in the senate can measure this partisanship.\r\n\r\n%% The Senate\r\n% Senators serve six-year terms and every two years about one-third\r\n% of the senate stands for reelection or new senators are elected.\r\n% So, a new \"Congress\" convenes every two years and has two year-long\r\n% \"Sessions\".  The first session was in 1789.  The 101-st Congress\r\n% began in 1989 and last year, 2025, is the First Session of the\r\n% 119-th Congress.\r\n\r\n%%\r\n%\r\n% <<division2025.png>>\r\n%\r\n% This bar chart shows the division between the\r\n% Republican and Democratic parties over our time period.\r\n% The data from the web site <https:\/\/www.senate.gov\/history\/partydiv.htm\r\n% party division> comes with the caveat,\r\n% \"The actual number of senators representing a particular party often\r\n% changes during a Congress, due to the death or resignation of a senator,\r\n% or as a consequence of a member changing parties.\"\r\n\r\n%% The Data\r\n% The web site <https:\/\/www.senate.gov www.senate.gov> has\r\n% year-by-year records of voting in the senate.  We are going to \r\n% look at 37 years, from 1989 to 2025.\r\n% For example, the URL\r\n%\r\n% <https:\/\/www.senate.gov\/legislative\/LIS\/roll_call_votes\/vote1162\/vote_116_2_00033.xml\r\n%   https: \/\/www.senate.gov\/legislative\/LIS\/roll_call_votes\/vote1162\/vote_116_2_00033.xml>\r\n%\r\n% points to the record of a roll call vote taken in the senate early in\r\n% 2020.  The congress number, 116, and the session, 2, each appear twice. \r\n% The 33 signifies this is the 33rd vote of this session.\r\n\r\n%%\r\n% Each roll-call vote is recorded in an XML file. \r\n% XML is the abbreviation for eXtensible Markup Language, an important\r\n% standard from the WWW Consortium defining a format for encoding\r\n% documents that is both human and machine readable.\r\n% I was pleased to find MATLAB Central File Exchange\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/28518-xml2struct\r\n% 28518-xml2struct> by Wouter Falkena.  As the function name implies,\r\n% this handy code \"converts an XML file into a MATLAB structure for\r\n% easy access to the data.\"\r\n\r\n%%\r\n% You can also use your browser to access the example URL and (a) examine \r\n% the XML, and (b) see why bills 33 and 34 from year 2020 are not typical\r\n% measures before the Senate.\r\n\r\n%% The Matrices\r\n% Once you find your way through the layers of structure that results from\r\n% the  XML, you will have many details about each senate roll call vote.\r\n% In particular, for each senator who voted, you will have a structure\r\n% with fields full name, last name, first name, party, state, vote,\r\n% and member id.\r\n\r\n%% \r\n% For each year, we create a matrix of +1s, -1s, and 0s.  A +1 is for\r\n% a vote of \"Yea\" or \"Guilty\", a -1 is a \"Nay\" or \"Not Guilty\", and a \r\n% 0 is for anything else, which includes \"Not Voting\", \"Present\" (abstain),\r\n% and something too complicated to explain called \"Present, Giving Live\r\n% Pair\".  Because there are 100 senators, the matrix has 100 rows. \r\n% The number of columns is the number of roll call votes taken that year.  \r\n% The matrices range in size from 100-by-163 for 2016 to \r\n% 100-by-613 for 1995.  \r\n\r\n%%\r\n% The XML is organized using last names of senators in alphabetic order REPLACE_WITH_DASH_DASH\r\n% Alexander (R-TN), Baldwin (D-WI), Barrasso (R-WY), ..., Young(R-IN).\r\n% At first, I tried to create matrices with rows in this order.   \r\n% But senators retire or die in midsession, so this ordering proved to be\r\n% difficult to manage correctly.  Ultimately, I decided to order the rows\r\n% by states.  Each state is allocated two rows; the name of the specific\r\n% senator occupying each row is irrelevant.  After the matrix for\r\n% a given year is complete, I reorder the rows so that all the senators\r\n% from each party are grouped together.  The one or two senators who\r\n% declare themselves to be independent (but who caucus with a major party)\r\n% are between the two parties.\r\n\r\n%%\r\n% Here are the matrices, 37 of them, one for each session from\r\n% 1989 to 2025.  A good way to see the\r\n% structure of these matrices is to view them as images.\r\n% Red is \"Yea\" or \"Guilty\", gold is \"Nay\" or \"Not Guilty\",\r\n% and white is not present, abstain or other.\r\n%\r\n% <<senate_gif1.gif>>\r\n%\r\n\r\n%% Partisanship\r\n% The SVD of these matrices provides the basis for our analysis.\r\n% The singular values decrease very rapidly with increasing index,\r\n% so the matrices can be well approximated by matrices of rank two.\r\n% When viewed from the record of roll call votes, the U. S. Senate\r\n% is nearly two-dimensional.\r\n\r\n%%\r\n% Let |A(y)| be the matrix of 1s, -1s and 0s summarizing the roll call\r\n% votes in year |y|.  Let\r\n%\r\n%   sigma = svd(A(y))\r\n%\r\n% Then the _partisanship_ for year |y| is defined usinng the third\r\n% singular value.\r\n%\r\n%   partianship = 1-sigma(3)\/sigma(1) \r\n%\r\n% This quantity measures how close the voting pattern is to\r\n% being two-dimensional.\r\n\r\n%% Compare\r\n% For example, 1991 is one of the least partisan years in our sample,\r\n% and 2025 is one of the most partisan years.\r\n% You can immediately see that 2025 has much less detailed structure than\r\n% 1991; it is closer to being two-dimensional\r\n% \r\n% <<A1991a.png>>\r\n%\r\n% <<A2025.png>>\r\n%\r\n\r\n%% Increasing Partisanship\r\n% This animation shows the distribution of the first ten singular values\r\n% for the years from 1989 to 2025.  The singular values are\r\n% normalized so that |1-sigma(1) = 0|. Then the third singular value is\r\n% highlighted. \r\n%\r\n% <<senate_gif2.gif>>\r\n%\r\n% Finally, here is this measure of partisanship for each year from 1989\r\n% to 2025, and a linear least squares fit.  With this much\r\n% scatter is the values, the exact fit can't be taken too seriously.\r\n% But there is definitely an upward trend.  Partisanship in the U. S. Senate\r\n% has increased from less than 70% thirty years ago to more than 80% today.\r\n%\r\n% <<partisanship_a.png>>\r\n%\r\n% \r\n##### SOURCE END ##### 581e808db466464aa3eed7e7508fa69e\r\n-->\r\n","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/cleve\/files\/partisanship-1.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><!--introduction-->\r\n<p>My first blog about SVD and Partisanship in the U. S. Senate was <a href=\"https:\/\/blogs.mathworks.com\/cleve\/2020\/08\/23\/svd-quantifies-increasing-partisanship-in-the-u-s-senate\/\">five years ago<\/a>. Today's post updates that to 2025.... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/cleve\/2026\/01\/12\/svd-measures-partisanship-in-the-u-s-senate\/\">read more >><\/a><\/p>","protected":false},"author":78,"featured_media":13519,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[32,16,30,1],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/13513"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/users\/78"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/comments?post=13513"}],"version-history":[{"count":7,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/13513\/revisions"}],"predecessor-version":[{"id":13531,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/posts\/13513\/revisions\/13531"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/media\/13519"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/media?parent=13513"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/categories?post=13513"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/cleve\/wp-json\/wp\/v2\/tags?post=13513"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}