ActBlue analysis

In [1]:
import json
import math
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np
import os
import pandas as pd
import psycopg2
import requests
import gender_guesser.detector as gender
In [2]:
%matplotlib inline

plt.style.use('ggplot')

pd.options.display.float_format = '{:,.2f}'.format
In [3]:
def read_or_save(name, func):
    path = 'pickles/' + name + '.pickle.gz'
    if (os.path.isfile(path)):
        return pd.read_pickle(path)
    else:
        result = func()
        os.makedirs('pickles', exist_ok=True)
        result.to_pickle(path)
        return result
In [4]:
committee_id = "C00401224"
year_since = 2013
In [5]:
with open("config.json") as f:
    conf = json.load(f)
conn = psycopg2.connect(
    dbname=conf['dbname'],
    user=conf['user'],
    host=conf['host'],
    password=conf['password']
)
conn.autocommit = True

How many reports are in the database?

Jan. 1, 2013 — now

In [6]:
filings_count = read_or_save(
    'filings_count',
    lambda: pd.read_sql("""
    SELECT count(*)
    FROM
      (SELECT filing_id
       FROM fec_filings
       UNION SELECT filing_id
       FROM fec_paper_filings) AS filings;
    """, con=conn)
)
filings_count
Out[6]:
count
0 433363

Are there other committees itemizing a large number of transfers?

Jan. 1, 2017 — now

In [7]:
transfer_committees = read_or_save(
    'transfer_committees',
    lambda: pd.read_sql("""
    SELECT filer_committee_id_number,
           fec_committees.name,
           count,
           sum
    FROM
        (SELECT filer_committee_id_number,
               count(*) AS count,
               sum(expenditure_amount) as sum
        FROM fec_expenditures
        JOIN fec_amended_filings using (filing_id)
        WHERE 
        -- filer_committee_id_number != '""" + committee_id + """' AND 
         extract(YEAR
                      FROM expenditure_date) >= 2017
          -- AND beneficiary_committee_fec_id IS NOT NULL
          AND form_type = 'SB23'
        GROUP BY filer_committee_id_number
        ORDER BY COUNT DESC
        LIMIT 10) as counts
    LEFT JOIN fec_committees
    ON fec_committees.id = filer_committee_id_number
    """, con=conn)
)

transfer_committees
Out[7]:
filer_committee_id_number name count sum
0 C00401224 ACTBLUE 30462320 919,575,587.04
1 C00632133 SWING LEFT 1675478 4,815,571.82
2 C00193433 EMILY'S LIST 130926 11,112,047.43
3 C00341396 MOVEON.ORG POLITICAL ACTION 76281 2,778,545.04
4 C00448696 SENATE CONSERVATIVES FUND 62895 6,828,088.98
5 C00552851 HOUSE FREEDOM FUND 23366 5,315,812.00
6 C00468314 DEMOCRACY ENGINE, INC., PAC 20138 5,347,428.25
7 C00252940 LEAGUE OF CONSERVATION VOTERS ACTION FUND 16429 3,175,549.50
8 C00432260 CLUB FOR GROWTH PAC 16056 4,449,005.99
9 C00608489 GREAT AMERICA PAC 11824 148,162.26

How much was raised from unitemized contributions versus itemized for the 2018 and 2014 cycles by congressional candidates of each party?

2014

Jan. 1, 2013 — Sept. 30, 2014

In [8]:
def calc_candidate_unitemized_by_party(cycle):
     return read_or_save(
            'candidate_unitemized_by_party_' + str(cycle)[2:],
            lambda: pd.read_sql("""
            SELECT CASE
                       WHEN cand_pty_affiliation = 'DEM' THEN 'Democrat'
                       WHEN cand_pty_affiliation = 'DFL' THEN 'Democrat'
                       WHEN cand_pty_affiliation = 'REP' THEN 'Republican'
                       ELSE 'third party'
                   END AS party,
                   -- cand_office,
                   count(DISTINCT cand_id) as candidates,
                   sum(col_a_individual_contributions_itemized) AS itemized,
                   sum(col_a_individual_contributions_unitemized) AS unitemized,
                   sum(col_a_total_individual_contributions) AS indivs
            FROM
              (SELECT DISTINCT ON (cand_pcc) *
               FROM fec_candidates
               WHERE
               cand_election_yr IN ('%(year_before)s','%(cycle)s') AND
             cand_pcc IS NOT NULL
               ORDER BY cand_pcc) AS cands
            JOIN
              (SELECT filing_id,
                      filer_committee_id_number,
                      col_a_individual_contributions_itemized,
                  col_a_individual_contributions_unitemized,
                  col_a_total_individual_contributions,
                  col_a_total_receipts,
                  col_a_total_disbursements,
                  coverage_from_date,
                  coverage_through_date
           FROM fec_campaign_summaries
           JOIN fec_amended_filings USING (filing_id)
           WHERE filing_id >= 2000
           UNION SELECT DISTINCT ON (filer_committee_id_number,
                                     coverage_from_date,
                                     coverage_through_date) filing_id,
                                    filer_committee_id_number,
                                    col_a_individual_contributions_itemized,
                                    col_a_individual_contributions_unitemized,
                                    col_a_total_individual_contributions,
                                    col_a_total_receipts,
                                    col_a_total_disbursements,
                                    coverage_from_date,
                                    coverage_through_date
           FROM fec_paper_campaign_summaries
           WHERE col_a_total_individual_contributions IS NOT NULL
           ORDER BY filer_committee_id_number,
                    coverage_through_date,
                    coverage_from_date,
                    filing_id DESC) AS summaries ON cand_pcc = filer_committee_id_number
        WHERE extract(YEAR
                      FROM coverage_through_date) >= %(year_before)s
          AND coverage_through_date <= '%(cycle)s-09-30'::date
          -- AND (col_a_total_receipts > 0
        --       OR col_a_total_disbursements > 0)
        GROUP BY -- cand_office,
                 party
        ORDER BY indivs DESC
        """, con=conn, params={"cycle":cycle,"year_before":cycle-1})
    )
    
candidate_unitemized_by_party_14 = calc_candidate_unitemized_by_party(2014)

candidate_unitemized_by_party_14
Out[8]:
party candidates itemized unitemized indivs
0 Republican 879 386,281,126.61 68,550,509.73 454,992,766.26
1 Democrat 669 340,445,390.26 81,131,227.89 421,581,550.15
2 third party 102 3,029,102.42 845,118.46 3,878,881.96

2018

Jan. 1, 2017 — Sept. 30, 2018

In [9]:
candidate_unitemized_by_party_18 = calc_candidate_unitemized_by_party(2018)

candidate_unitemized_by_party_18
Out[9]:
party candidates itemized unitemized indivs
0 Democrat 1301 696,647,516.34 276,459,159.83 975,229,121.92
1 Republican 952 381,996,769.92 86,775,416.23 469,125,458.15
2 third party 155 10,706,732.22 10,062,841.59 20,823,298.81

What proportion is the increase in unitemized contribs for Democrats?

In [10]:
candidate_unitemized_by_party_18[candidate_unitemized_by_party_18['party'] == 'Democrat']['unitemized'].sum()/candidate_unitemized_by_party_14[candidate_unitemized_by_party_14['party'] == 'Democrat']['unitemized'].sum()
Out[10]:
3.407555475492508

Which ActBlue reports do we have?

Jan. 1, 2013 — Sept. 30, 2018

In [11]:
actblue_summaries = read_or_save(
    'actblue_summaries',
    lambda: pd.read_sql("""
    SELECT *
    FROM fec_pac_summaries
    JOIN fec_amended_filings USING (filing_id)
    WHERE filer_committee_id_number = '""" + committee_id + """'
    AND extract(year from coverage_through_date) >= """ + str(year_since) + """
    ORDER BY coverage_through_date DESC;
    """, con=conn, parse_dates={
        'coverage_from_date': '%Y-%m-%d',
        'coverage_through_date': '%Y-%m-%d'
    })
)

with pd.option_context('display.max_rows', None, 'display.max_columns', None):
    display(actblue_summaries[[
        'filing_id',
        'coverage_from_date',
        'coverage_through_date',
        'report_code',
        'col_a_total_contributions'
    ]])
filing_id coverage_from_date coverage_through_date report_code col_a_total_contributions
0 1277598 2018-09-01 2018-09-30 M10 144,336,242.30
1 1263179 2018-08-01 2018-08-31 M9 88,719,194.67
2 1258193 2018-07-01 2018-07-31 M8 60,945,546.97
3 1251343 2018-06-01 2018-06-30 M7 63,088,119.19
4 1240253 2018-05-01 2018-05-31 M6 43,130,233.11
5 1233520 2018-04-01 2018-04-30 M5 38,328,646.45
6 1225971 2018-03-01 2018-03-31 M4 57,825,086.02
7 1215697 2018-02-01 2018-02-28 M3 41,932,847.30
8 1224404 2018-01-01 2018-01-31 M2 32,937,704.67
9 1224416 2017-12-01 2017-12-31 YE 51,181,861.72
10 1219434 2017-11-01 2017-11-30 M12 36,180,318.82
11 1219420 2017-10-01 2017-10-31 M11 29,341,844.16
12 1218757 2017-09-01 2017-09-30 M10 34,193,318.59
13 1217404 2017-08-01 2017-08-31 M9 22,119,367.28
14 1217370 2017-07-01 2017-07-31 M8 19,876,390.23
15 1217173 2017-06-01 2017-06-30 M7 37,393,287.73
16 1217152 2017-05-01 2017-05-31 M6 38,967,198.82
17 1216926 2017-04-01 2017-04-30 M5 31,056,313.27
18 1216920 2017-03-01 2017-03-31 M4 36,312,800.17
19 1216764 2017-02-01 2017-02-28 M3 26,339,952.47
20 1189990 2017-01-01 2017-01-31 M2 20,866,545.47
21 1189983 2016-11-29 2016-12-31 YE 14,665,549.11
22 1190211 2016-10-20 2016-11-28 30G 69,306,148.22
23 1167570 2016-10-01 2016-10-19 12G 38,988,748.30
24 1111238 2016-09-01 2016-09-30 M10 49,154,145.94
25 1100745 2016-08-01 2016-08-31 M9 32,940,792.06
26 1148387 2016-07-01 2016-07-31 M8 27,941,112.01
27 1148378 2016-06-01 2016-06-30 M7 35,458,306.24
28 1148219 2016-05-01 2016-05-31 M6 36,415,717.72
29 1148088 2016-04-01 2016-04-30 M5 45,279,893.80
30 1147747 2016-03-01 2016-03-31 M4 68,402,635.49
31 1056917 2016-02-01 2016-02-29 M3 55,899,769.67
32 1051660 2016-01-01 2016-01-31 M2 30,906,698.66
33 1047732 2015-07-01 2015-12-31 YE 111,428,188.85
34 1034155 2015-06-23 2015-06-30 MY 10,048,788.95
35 1034148 2015-06-18 2015-06-22 30R 1,918,585.61
36 1034000 2015-05-26 2015-06-17 12P 10,928,634.14
37 1033935 2015-05-14 2015-05-25 30S 4,060,610.09
38 1024737 2015-04-01 2015-05-13 12R 14,243,151.38
39 1024649 2015-03-01 2015-03-31 M4 10,850,839.44
40 1024632 2015-02-01 2015-02-28 M3 5,728,485.60
41 1024608 2015-01-01 2015-01-31 M2 5,341,242.90
42 989398 2014-11-25 2014-12-31 YE 6,399,647.20
43 980316 2014-10-16 2014-11-24 30G 40,095,025.02
44 964963 2014-10-01 2014-10-15 12G 19,475,785.64
45 961472 2014-09-01 2014-09-30 M10 32,945,251.74
46 952738 2014-08-01 2014-08-31 M9 19,828,963.36
47 946367 2014-07-01 2014-07-31 M8 17,165,044.18
48 942637 2014-06-01 2014-06-30 M7 17,413,165.87
49 932286 2014-05-01 2014-05-31 M6 11,108,153.52
50 926005 2014-04-01 2014-04-30 M5 9,572,387.13
51 921401 2014-03-01 2014-03-31 M4 15,327,609.20
52 912211 2014-02-01 2014-02-28 M3 8,488,177.31
53 907993 2014-01-01 2014-01-31 M2 5,899,101.82
54 903093 2013-12-01 2013-12-31 YE 8,291,620.84
55 897812 2013-11-01 2013-11-30 M12 5,497,959.94
56 895380 2013-10-01 2013-10-31 M11 7,244,311.04
57 892784 2013-09-01 2013-09-30 M10 9,559,996.38
58 888139 2013-08-01 2013-08-31 M9 4,083,446.94
59 884895 2013-07-01 2013-07-31 M8 4,627,012.69
60 880507 2013-06-01 2013-06-30 M7 7,321,587.76
61 874134 2013-05-01 2013-05-31 M6 5,505,206.65
62 871793 2013-04-01 2013-04-30 M5 5,822,094.62
63 868286 2013-03-01 2013-03-31 M4 6,887,038.10
64 861246 2013-02-01 2013-02-28 M3 5,211,370.73
65 857384 2013-01-01 2013-01-31 M2 2,931,148.52

Are there any reports that FEC.gov has that we don't or vice versa?

Jan. 1, 2013 — now

In [12]:
def get_reports(committee_id):
    base = "https://api.open.fec.gov/v1/"
    url = base + "committee/" + committee_id + "/reports/?api_key=" + conf['fec_key'] + "&is_amended=False&per_page=100"

    return pd.DataFrame(requests.get(url).json()['results'])

actblue_api_summaries = read_or_save('actblue_api_summaries', lambda: get_reports(committee_id))
pd.to_numeric(actblue_api_summaries['calendar_ytd'])
actblue_api_summaries = actblue_api_summaries[actblue_api_summaries['calendar_ytd'] >= year_since]
actblue_api_summaries[['file_number','calendar_ytd']]

pd.DataFrame(pd.concat([actblue_api_summaries['file_number'],
                        actblue_summaries['filing_id']]).drop_duplicates(keep=False))
Out[12]:
0

How many itemized federal individual contributions from ActBlue are we analyzing?

Jan. 1, 2013 — now

In [13]:
def cycle(year):
    return math.ceil(float(year) / 2.) * 2

assert (cycle(2013) == 2014 and
    cycle(2014) == 2014 and
    cycle(2015) == 2016 and
    cycle(2016) == 2016 and
    cycle(2017) == 2018 and
    cycle(2018) == 2018),"unexpected cycle output"
In [14]:
actblue_contrib_count_by_year = read_or_save(
    'actblue_contrib_count_by_year',
    lambda: pd.read_sql("""
    -- DROP MATERIALIZED VIEW actblue_contribs;

    CREATE MATERIALIZED VIEW IF NOT EXISTS actblue_contribs AS
    SELECT contribs.*,
           fec_expenditures.election_code,
           beneficiary_committee_fec_id,
           beneficiary_candidate_fec_id,
           beneficiary_candidate_state,
           beneficiary_candidate_office,
           coalesce(cand_comms.cand_id,cands.cand_id) AS cand_id,
           coalesce(cand_comms.cand_pty_affiliation,cands.cand_pty_affiliation) AS cand_pty_affiliation,
           coalesce(cand_comms.cand_office_st,cands.cand_office_st) AS cand_office_st,
           coalesce(cand_comms.cand_office,cands.cand_office) AS cand_office,
           coalesce(cand_comms.cand_pcc,cands.cand_pcc) AS cand_pcc
    FROM
      (SELECT fec_contributions.filing_id,
              transaction_id,
              contributor_last_name,
              contributor_first_name,
              contributor_street_1,
              contributor_city,
              contributor_state,
              contributor_zip_code,
              contribution_date,
              contribution_amount,
              contributor_employer,
              contributor_occupation,
              memo_text_description
       FROM fec_contributions
       WHERE filing_id IN
           (SELECT filing_id
            FROM fec_pac_summaries
            JOIN fec_amended_filings USING (filing_id)
            WHERE filer_committee_id_number = 'C00401224'
              AND extract(YEAR
                          FROM coverage_through_date) >= 2013
            ORDER BY coverage_through_date DESC)
         AND form_type = 'SA11AI') AS contribs
    LEFT JOIN fec_expenditures ON fec_expenditures.filing_id IN
      (SELECT filing_id
       FROM fec_pac_summaries
       JOIN fec_amended_filings USING (filing_id)
       WHERE filer_committee_id_number = 'C00401224'
         AND extract(YEAR
                     FROM coverage_through_date) >= 2013
       ORDER BY coverage_through_date DESC)
    AND fec_expenditures.form_type = 'SB23'
    AND 'SB23_' || replace(transaction_id,'SA11AI_','') = transaction_id_number
    LEFT JOIN
      (SELECT DISTINCT ON (cand_id) cand_id,
                          cand_pcc,
                          cand_pty_affiliation,
                          cand_office_st,
                          cand_office
       FROM fec_candidates
       ORDER BY cand_id,
                cand_election_yr::int DESC) AS cands ON cands.cand_id = beneficiary_candidate_fec_id
                AND beneficiary_committee_fec_id NOT IN
                  (SELECT id
                   FROM fec_committees
                   WHERE designation = 'J')
    LEFT JOIN
      (SELECT DISTINCT ON (cand_pcc) cand_id,
                          cand_pcc,
                          cand_pty_affiliation,
                          cand_office_st,
                          cand_office
       FROM fec_candidates
       ORDER BY cand_pcc,
                cand_election_yr::int DESC) AS cand_comms ON cand_comms.cand_pcc = beneficiary_committee_fec_id;

    GRANT ALL ON TABLE actblue_contribs TO redash_default;
    GRANT ALL ON TABLE actblue_contribs TO politics;

    -- REFRESH MATERIALIZED VIEW actblue_contribs;
    -- ANALYZE actblue_contribs;

    SELECT extract(YEAR
                   FROM contribution_date) AS YEAR,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    GROUP BY extract(YEAR
                     FROM contribution_date);
    """, con=conn)
)

actblue_contrib_count_by_year['cycle'] = actblue_contrib_count_by_year[~actblue_contrib_count_by_year['year'].isna()]['year'].apply(cycle)

actblue_contrib_count_by_cycle = pd.DataFrame(
    actblue_contrib_count_by_year.groupby(actblue_contrib_count_by_year['cycle'])['count','sum'].sum()
)
actblue_contrib_count_by_cycle
Out[14]:
count sum
cycle
2,014.00 11833542 276,701,162.20
2,016.00 30578103 679,907,198.18
2,018.00 37861126 955,078,929.41

How much in itemized federal individual contributions to Congress are we analyzing?

Jan. 1, 2013 — now

In [15]:
actblue_congress_contrib_count_by_year = read_or_save(
    'actblue_congress_contrib_totals',
    lambda: pd.read_sql("""
    SELECT extract(YEAR
                   FROM contribution_date) AS YEAR,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE coalesce(beneficiary_candidate_office,cand_office) IN ('H','S')
    GROUP BY extract(YEAR
                     FROM contribution_date);
    """, con=conn)
)

actblue_congress_contrib_count_by_year['cycle'] = actblue_congress_contrib_count_by_year[~actblue_congress_contrib_count_by_year['year'].isna()]['year'].apply(cycle)

actblue_congress_contrib_count_by_cycle = pd.DataFrame(
    actblue_congress_contrib_count_by_year.groupby(actblue_congress_contrib_count_by_year['cycle'])['count','sum'].sum()
)
actblue_congress_contrib_count_by_cycle
Out[15]:
count sum
cycle
2,014.00 3361213 113,951,310.78
2,016.00 6747187 222,107,175.60
2,018.00 15272992 563,685,031.21
In [16]:
actblue_congress_contrib_count_by_cycle.to_csv('data/actblue_contribs_by_cycle.csv')

How much in itemized federal individual contributions to congressional candidates are we analyzing to date?

In [17]:
actblue_congress_contrib_totals_to_date = read_or_save(
    'actblue_congress_contrib_totals_to_date',
    lambda: pd.read_sql("""
    SELECT extract(YEAR
                   FROM contribution_date) AS YEAR,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE coalesce(beneficiary_candidate_office,cand_office) IN ('H',
                                           'S')
      AND ((contribution_date >= '2017-01-01'
           AND contribution_date <= '2018-09-30')
      OR (contribution_date >= '2015-01-01'
          AND contribution_date <= '2016-09-30')
      OR (contribution_date >= '2013-01-01'
          AND contribution_date <= '2014-09-30'))
    GROUP BY extract(YEAR
                     FROM contribution_date);
    """, con=conn)
)

actblue_congress_contrib_totals_to_date['cycle'] = actblue_congress_contrib_totals_to_date[~actblue_congress_contrib_totals_to_date['year'].isna()]['year'].apply(cycle)

actblue_congress_contrib_count_by_cycle_to_date = pd.DataFrame(
    actblue_congress_contrib_totals_to_date.groupby(actblue_congress_contrib_totals_to_date['cycle'])['count','sum'].sum()
)
actblue_congress_contrib_count_by_cycle_to_date
Out[17]:
count sum
cycle
2014 2465270 86,840,834.49
2016 4405520 164,764,579.43
2018 15272992 563,685,031.21

How have total contributions to ActBlue changed over reporting periods?

Jan. 1, 2013 — now

In [18]:
contribs_over_time = actblue_summaries[['coverage_through_date','col_a_total_contributions']]

# https://scentellegher.github.io/programming/2017/05/24/pandas-bar-plot-with-formatted-dates.html
contribs_over_time.set_index('coverage_through_date',inplace=True)

fig, ax = plt.subplots(figsize=(12,7))

ax.xaxis.set_major_locator(mdates.YearLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))

# https://matplotlib.org/examples/pylab_examples/custom_ticker1.html
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, p: '$%1.fM' % (x*1e-6)))

ax.bar(contribs_over_time.index, contribs_over_time['col_a_total_contributions'], width=5)

ax.set_title('Total contributions by reporting period')
Out[18]:
Text(0.5,1,'Total contributions by reporting period')

How much did donors give through ActBlue overall by day?

In [19]:
actblue_contribs_by_day = read_or_save(
    'actblue_contribs_by_day',
    lambda: pd.read_sql("""
    SELECT contribution_date,
           sum(contribution_amount),
           count(*)
    FROM actblue_contribs
    -- where extract(year from contribution_date) >= 2017 and
    -- where cand_office in ('S','H')
    GROUP BY contribution_date
    """, con=conn)
)

actblue_contribs_by_day.head(10)
Out[19]:
contribution_date sum count
0 2013-01-01 35,189.95 1749
1 2013-01-02 20,131.95 991
2 2013-01-03 69,351.58 4358
3 2013-01-04 34,018.57 1400
4 2013-01-05 17,418.41 666
5 2013-01-06 12,100.46 642
6 2013-01-07 40,888.69 1919
7 2013-01-08 39,004.71 2779
8 2013-01-09 48,775.86 1412
9 2013-01-10 73,739.31 4289
In [20]:
actblue_contribs_by_day.to_csv('data/actblue_contribs_by_day.csv')

How much did donors give through ActBlue to congressional candidates by day?

In [21]:
actblue_congress_contribs_by_day = read_or_save(
    'actblue_congress_contribs_by_day',
    lambda: pd.read_sql("""
    SELECT contribution_date,
           sum(contribution_amount),
           count(*)
    FROM actblue_contribs
    -- where extract(year from contribution_date) >= 2017 and
    where coalesce(beneficiary_candidate_office,cand_office) in ('S','H')
    GROUP BY contribution_date
    """, con=conn)
)

actblue_congress_contribs_by_day.head(10)
Out[21]:
contribution_date sum count
0 2013-01-01 9,878.94 167
1 2013-01-02 8,158.56 304
2 2013-01-03 5,105.80 201
3 2013-01-04 5,070.50 159
4 2013-01-05 5,453.94 140
5 2013-01-06 1,922.65 75
6 2013-01-07 3,934.05 50
7 2013-01-08 8,805.86 176
8 2013-01-09 29,203.31 354
9 2013-01-10 10,161.63 335
In [22]:
actblue_congress_contribs_by_day.to_csv('data/actblue_congress_contribs_by_day.csv')
In [23]:
contribs_by_day = actblue_congress_contribs_by_day[['contribution_date','sum']]

# https://scentellegher.github.io/programming/2017/05/24/pandas-bar-plot-with-formatted-dates.html
contribs_by_day.set_index('contribution_date',inplace=True)

fig, ax = plt.subplots(figsize=(12,7))

ax.xaxis.set_major_locator(mdates.YearLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))

# https://matplotlib.org/examples/pylab_examples/custom_ticker1.html
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, p: '$%1.fM' % (x*1e-6)))

ax.bar(contribs_by_day.index, contribs_by_day['sum'], width=5)

ax.set_title('Congressional contribution totals by day')
Out[23]:
Text(0.5,1,'Congressional contribution totals by day')

How have total federal contributions to ActBlue changed between cycles?

Jan. 1, 2013 — now

In [24]:
actblue_summaries['cycle'] = actblue_summaries.coverage_through_date.dt.year.apply(cycle)

contribs_by_cycle = pd.DataFrame(
    actblue_summaries.groupby(actblue_summaries['cycle'])['col_a_total_contributions'].sum()
)
contribs_by_cycle
Out[24]:
col_a_total_contributions
cycle
2014 276,701,106.20
2016 679,908,044.18
2018 955,072,819.41

Cycle to date

In [25]:
actblue_summaries['cycle'] = actblue_summaries.coverage_through_date.dt.year.apply(cycle)

actblue_summaries_to_date = actblue_summaries[((actblue_summaries['coverage_through_date'] >= '2017-01-01') &
                                              (actblue_summaries['coverage_through_date'] <= '2018-09-30')) |
                                              ((actblue_summaries['coverage_through_date'] >= '2015-01-01') &
                                              (actblue_summaries['coverage_through_date'] <= '2016-09-30')) | 
                                              ((actblue_summaries['coverage_through_date'] >= '2013-01-01') &
                                              (actblue_summaries['coverage_through_date'] <= '2014-09-30'))]

contribs_by_cycle = pd.DataFrame(
    actblue_summaries_to_date.groupby(actblue_summaries_to_date['cycle'])['col_a_total_contributions'].sum()
)
contribs_by_cycle
Out[25]:
col_a_total_contributions
cycle
2014 210,730,648.34
2016 556,947,598.55
2018 955,072,819.41
In [26]:
# https://scentellegher.github.io/programming/2017/05/24/pandas-bar-plot-with-formatted-dates.html
# contribs_by_year.set_index('coverage_through_date',inplace=True)

fig, ax = plt.subplots(figsize=(10,7))

ax.xaxis.set_major_locator(mdates.YearLocator())
# ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))

# https://matplotlib.org/examples/pylab_examples/custom_ticker1.html
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, p: '$%1.fM' % (x*1e-6)))

ax.bar(contribs_by_cycle.index, contribs_by_cycle['col_a_total_contributions'], width=0.8)

ax.set_title('Total contributions by cycle')
Out[26]:
Text(0.5,1,'Total contributions by cycle')

Which committees receive contributions through ActBlue?

Jan. 1, 2013 — now

In [27]:
actblue_transfers = read_or_save(
    'actblue_transfers',
    lambda: pd.read_sql("""
    SELECT fec_committees.name,
           totals.*
    FROM
      (SELECT beneficiary_committee_fec_id,
              count(*),
              sum(contribution_amount)
       FROM actblue_contribs
       GROUP BY beneficiary_committee_fec_id) AS totals
    LEFT JOIN fec_committees ON beneficiary_committee_fec_id = fec_committees.id
    """, con=conn)
)
actblue_transfers.sort_values(by=['sum'], ascending=False).head(20)
Out[27]:
name beneficiary_committee_fec_id count sum
0 DCCC C00000935 11814400 246,490,447.00
1466 BERNIE 2016 C00577130 7674980 198,901,495.65
26 DSCC C00042366 3486394 98,566,985.16
3693 None None 16702739 75,348,173.81
1408 END CITIZENS UNITED C00573261 3771328 50,988,050.92
670 BETO FOR TEXAS C00501197 1150586 45,538,960.43
2089 JON OSSOFF FOR CONGRESS C00630426 1430332 27,468,759.69
2475 DOUG JONES FOR SENATE COMMITTEE C00640623 767342 22,177,988.84
1509 PROGRESSIVE TURNOUT PROJECT C00580068 1499109 20,580,459.30
11 DNC SERVICES CORP./DEM. NAT'L COMMITTEE C00010603 790624 19,491,595.88
365 GILLIBRAND FOR SENATE C00413914 417112 14,907,247.32
429 MCCASKILL FOR MISSOURI C00431304 350808 14,054,926.91
239 CHC BOLD PAC C00365536 992271 13,222,983.83
1391 KAMALA HARRIS FOR SENATE C00571919 439036 12,907,094.64
626 HOUSE MAJORITY PAC C00495028 616684 12,337,803.91
515 PROGRESSIVE CHANGE CAMPAIGN COMMITTEE C00458000 1303655 12,224,057.76
669 ELIZABETH FOR MA INC C00500843 741738 12,216,893.18
246 DEMOCRACY FOR AMERICA C00370007 769917 12,170,215.96
835 GIFFORDS PAC C00540443 422019 11,489,153.57
1609 MAGGIE FOR NH C00588772 345062 10,460,434.29

How much of this is a contribution to ActBlue itself?

Jan. 1, 2013 — now

In [28]:
actblue_itself = read_or_save(
    'actblue_itself',
    lambda: pd.read_sql("""
    SELECT count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE memo_text_description = 'Contribution to ActBlue'
    """, con=conn)
)
actblue_itself
Out[28]:
count sum
0 16478679 48,182,124.56

How many Democratic campaigns received contributions through ActBlue? What percentage of Democratic campaigns is that?

Jan. 1, 2017 — Sept. 30, 2018

In [29]:
actblue_proportion = read_or_save(
    'actblue_proportion',
    lambda: pd.read_sql("""
    SELECT actblue,
           count(*)
    FROM
      (SELECT cand_id,
              cand_pcc,
              CASE
                  WHEN COUNT IS NOT NULL THEN TRUE
                  ELSE FALSE
              END AS actblue
       FROM (SELECT DISTINCT ON (cand_id,
                               cand_pcc) *
           FROM fec_candidates
           WHERE cand_election_yr IN ('2018','2017')
             AND cand_pcc IS NOT NULL
             AND cand_pty_affiliation IN ('DFL',
                                      'DEM')
           ORDER BY cand_id,
                    cand_pcc) AS cands
       LEFT JOIN
         (SELECT fec_committees.name,
                 totals.*
          FROM
            (SELECT beneficiary_committee_fec_id,
                    count(*) AS COUNT,
                    sum(contribution_amount)
             FROM actblue_contribs
             WHERE extract(YEAR
                                FROM contribution_date) >= 2017
             GROUP BY beneficiary_committee_fec_id) AS totals
          LEFT JOIN fec_committees ON beneficiary_committee_fec_id = fec_committees.id) AS actblue_committees ON cand_pcc = beneficiary_committee_fec_id) AS actblue_candidates
    GROUP BY actblue
    """, con=conn)
)

actblue_proportion['percent'] = actblue_proportion['count']/actblue_proportion['count'].sum()*100

actblue_proportion
Out[29]:
actblue count percent
0 False 235 15.12
1 True 1319 84.88

Rise of ActBlue: What percent of Democratic congresssional campaign cash from individuals was raised through ActBlue by cycle? How about 2014?

In [30]:
def calc_actblue_proportion_amount(cycle):
    return read_or_save(
        'actblue_proportion_amount_' + str(cycle)[2:],
        lambda: pd.read_sql('''
        WITH cands AS
          (SELECT DISTINCT ON (cand_pcc) *
           FROM fec_candidates
           WHERE cand_election_yr IN ('%(year_before)s',
                                      '%(cycle)s')
             AND cand_pty_affiliation IN ('DFL',
                                          'DEM')
             AND cand_pcc IS NOT NULL
           ORDER BY cand_pcc),
             candidate_totals AS
          (SELECT cand_id,
                  cand_pcc,
                  cand_name,
                  cand_office,
                  cand_office_st,
                  cand_office_district,
                  cand_election_yr,
                  coverage_from_date,
                  coverage_through_date,
                  col_a_total_individual_contributions
           FROM cands
           JOIN fec_campaign_summaries ON cand_pcc = filer_committee_id_number
           JOIN fec_amended_filings USING (filing_id)
           WHERE extract(YEAR
                         FROM coverage_through_date) >= %(year_before)s
             AND coverage_through_date <= '%(cycle)s-09-30'::date
             AND filing_id >= 2000
           UNION SELECT cand_id,
                        cand_pcc,
                        cand_name,
                        cand_office,
                        cand_office_st,
                        cand_office_district,
                        cand_election_yr,
                        coverage_from_date,
                        coverage_through_date,
                        col_a_total_individual_contributions
           FROM cands
           JOIN
             (SELECT DISTINCT ON (filer_committee_id_number,
                                  coverage_from_date,
                                  coverage_through_date) filing_id,
                                 filer_committee_id_number,
                                 col_a_total_individual_contributions,
                                 coverage_from_date,
                                 coverage_through_date
              FROM fec_paper_campaign_summaries
              WHERE col_a_total_individual_contributions IS NOT NULL
              ORDER BY filer_committee_id_number,
                       coverage_through_date,
                       coverage_from_date,
                       filing_id DESC) AS paper_totals ON cand_pcc = filer_committee_id_number
           WHERE extract(YEAR
                         FROM coverage_through_date) >= %(year_before)s
             AND coverage_through_date <= '%(cycle)s-09-30'::date)
        SELECT  cand_pcc,
                max(cand_name) as cand_name,
                max(cand_office) as cand_office,
                max(cand_office_st) as cand_office_st,
                max(cand_office_district) as cand_office_district,
                max(cand_election_yr) as cand_election_yr,
               array_agg(coverage_from_date) AS from_dates,
               array_agg(coverage_through_date) AS through_dates,
               sum(col_a_total_individual_contributions) AS committee_total,
               sum(actblue_total) AS actblue_total
        FROM
          (SELECT candidate_totals.cand_pcc,
                max(candidate_totals.cand_name) as cand_name,
                max(candidate_totals.cand_office) as cand_office,
                max(candidate_totals.cand_office_st) as cand_office_st,
                max(candidate_totals.cand_office_district) as cand_office_district,
                max(candidate_totals.cand_election_yr) as cand_election_yr,
                  coverage_from_date,
                  coverage_through_date,
                  col_a_total_individual_contributions,
                  sum(contribution_amount) AS actblue_total,
                  count(*) as actblue_count
           FROM candidate_totals
           LEFT JOIN actblue_contribs ON extract(YEAR
                                                 FROM coverage_through_date) >= %(year_before)s
           AND coverage_through_date <= '%(cycle)s-09-30'::date
           AND actblue_contribs.cand_pcc = candidate_totals.cand_pcc
           AND coverage_from_date <= contribution_date
           AND coverage_through_date >= contribution_date
           GROUP BY candidate_totals.cand_pcc,
                    col_a_total_individual_contributions,
                    coverage_from_date,
                    coverage_through_date) AS totals
        GROUP BY cand_pcc
        ''',con=conn,params={"cycle":cycle,"year_before":cycle-1})
    )

actblue_proportion_amount = calc_actblue_proportion_amount(2018)
In [31]:
actblue_proportion_amount['percent'] = actblue_proportion_amount['actblue_total']/actblue_proportion_amount['committee_total']
In [32]:
str(round(actblue_proportion_amount['actblue_total'].sum()/actblue_proportion_amount['committee_total'].sum()*100,2)) + " percent of contributions from individuals to Democratic campaigns came through ActBlue in the 2018 cycle (Jan. 1, 2017 — Sept/. 30, 2018)"
    
Out[32]:
'55.02 percent of contributions from individuals to Democratic campaigns came through ActBlue in the 2018 cycle (Jan. 1, 2017 — Sept/. 30, 2018)'
In [33]:
actblue_proportion_amount_14 = calc_actblue_proportion_amount(2014)

str(round(actblue_proportion_amount_14['actblue_total'].sum()/actblue_proportion_amount_14['committee_total'].sum()*100,2)) + " percent of contributions from individuals to Democratic campaigns came through ActBlue in the 2014 cycle (Jan. 1, 2013 — Sept. 30, 2014)"
Out[33]:
'19.43 percent of contributions from individuals to Democratic campaigns came through ActBlue in the 2014 cycle (Jan. 1, 2013 — Sept. 30, 2014)'

What's the ActBlue proportion by candidate?

In [34]:
actblue_proportion_amount[(~actblue_proportion_amount['percent'].isna()) & (actblue_proportion_amount['committee_total'] > 30000)].sort_values(by=['actblue_total'],ascending=False).head(20).sort_values(by=['percent'],ascending=False)
Out[34]:
cand_pcc cand_name cand_office cand_office_st cand_office_district cand_election_yr from_dates through_dates committee_total actblue_total percent
1143 C00667964 O'CONNOR, DANIEL JAY H OH 12 2018 [2018-04-19, 2018-07-19, 2018-04-01, 2018-01-0... [2018-06-30, 2018-08-27, 2018-04-18, 2018-03-3... 6,509,845.87 6,060,188.00 0.93
309 C00630426 OSSOFF, T. JONATHAN H GA 06 2017 [2018-01-01, 2017-10-01, 2017-07-11, 2017-06-0... [2018-03-31, 2017-12-31, 2017-09-30, 2017-07-1... 29,536,942.08 27,468,759.69 0.93
540 C00640623 JONES, DOUG S AL 00 2018 [2017-07-27, 2018-07-01, 2018-01-02, 2017-07-0... [2017-09-30, 2018-09-30, 2018-03-31, 2017-07-2... 23,961,141.21 22,212,934.94 0.93
331 C00632232 QUIST, ROBERT E. H MT 00 2017 [2017-06-15, 2017-04-01, 2018-04-01, 2018-01-0... [2017-06-30, 2017-05-05, 2018-06-30, 2018-03-3... 6,613,029.07 5,815,577.72 0.88
463 C00638510 JANZ, ANDREW H CA 22 2018 [2018-01-01, 2018-07-01, 2018-05-17, 2018-04-0... [2018-03-31, 2018-09-30, 2018-06-30, 2018-05-1... 7,091,195.60 6,205,223.06 0.88
97 C00413914 GILLIBRAND, KIRSTEN ELIZABETH S NY 00 2018 [2017-07-01, 2018-04-01, 2018-01-01, 2017-04-0... [2017-09-30, 2018-06-06, 2018-03-31, 2017-06-3... 15,593,188.69 13,168,962.00 0.84
908 C00657411 LAMB, CONOR H PA 17 2018 [2018-01-01, 2018-04-26, 2018-02-22, 2018-04-0... [2018-02-21, 2018-06-30, 2018-04-02, 2018-04-2... 7,767,411.81 6,469,653.12 0.83
608 C00647537 BRYCE, RANDY H WI 01 2018 [2017-06-01, 2017-10-01, 2018-07-26, 2018-01-0... [2017-06-30, 2017-12-31, 2018-09-30, 2018-03-3... 7,085,886.53 5,318,170.18 0.75
163 C00501197 O'ROURKE, ROBERT BETO H TX 16 2018 [2018-07-01, 2017-10-01, 2018-02-15, 2017-01-0... [2018-09-30, 2017-12-31, 2018-03-31, 2017-03-3... 61,566,975.15 45,412,197.04 0.74
143 C00492645 MURPHY, CHRISTOPHER S MR S CT 00 2018 [2017-04-01, 2017-01-01, 2017-10-01, 2018-04-2... [2017-06-30, 2017-03-31, 2017-12-31, 2018-06-3... 10,304,270.24 7,022,947.51 0.68
266 C00606939 ROSEN, JACKY H NV 03 2018 [2018-01-01, 2017-10-01, 2018-04-01, 2017-07-0... [2018-03-31, 2017-12-31, 2018-05-23, 2017-09-3... 13,642,423.24 9,213,189.77 0.68
173 C00505552 HEITKAMP, HEIDI S ND 00 2018 [2017-10-01, 2017-04-01, 2018-05-24, 2018-01-0... [2017-12-31, 2017-06-30, 2018-06-30, 2018-03-3... 9,265,613.81 5,778,155.37 0.62
110 C00431304 MCCASKILL, CLAIRE S MO 00 2018 [2017-10-01, 2017-04-01, 2018-01-01, 2018-07-0... [2017-12-31, 2017-06-30, 2018-03-31, 2018-07-1... 23,480,677.90 13,614,383.78 0.58
179 C00508804 SINEMA, KYRSTEN S AZ 00 2018 [2017-07-01, 2018-04-01, 2018-07-01, 2018-01-0... [2017-09-30, 2018-06-30, 2018-08-08, 2018-03-3... 12,572,778.97 6,667,888.43 0.53
162 C00500843 WARREN, ELIZABETH S MA 00 2018 [2017-10-01, 2018-08-16, 2017-01-01, 2017-04-0... [2017-12-31, 2018-09-30, 2017-03-31, 2017-06-3... 19,795,056.37 10,140,738.44 0.51
109 C00431056 CASEY, ROBERT P JR S PA 00 2018 [2017-04-01, 2018-04-01, 2018-04-26, 2017-07-0... [2017-06-30, 2018-04-25, 2018-06-30, 2017-09-3... 12,595,706.39 6,059,819.92 0.48
58 C00344051 NELSON, BILL S FL 00 2018 [2018-01-01, 2018-04-01, 2017-10-01, 2018-08-0... [2018-03-31, 2018-06-30, 2017-12-31, 2018-09-3... 20,030,409.53 9,294,124.00 0.46
95 C00412304 TESTER, JON S MT 00 2018 [2018-01-01, 2018-05-17, 2018-04-01, 2017-01-0... [2018-03-31, 2018-06-30, 2018-05-16, 2017-03-3... 12,239,218.79 5,246,677.28 0.43
29 C00264697 BROWN, SHERROD S OH 00 2018 [2018-01-01, 2017-01-01, 2018-07-01, 2018-04-0... [2018-03-31, 2017-03-31, 2018-09-30, 2018-04-1... 16,123,323.01 6,739,539.79 0.42
49 C00326801 BALDWIN, TAMMY S WI 00 2018 [2018-01-01, 2018-07-26, 2017-01-01, 2018-07-0... [2018-03-31, 2018-09-30, 2017-03-31, 2018-07-2... 21,173,192.85 8,424,141.80 0.40
In [35]:
actblue_proportion_amount[(~actblue_proportion_amount['percent'].isna()) & (actblue_proportion_amount['percent'] <= 1) & (actblue_proportion_amount['committee_total'] > 20000)].sort_values(by=['percent'],ascending=False).to_csv('data/actblue_proportion.csv')

How much did candidates raise from ActBlue?

In [36]:
actblue_cand_totals = read_or_save(
    'actblue_cand_totals',
    lambda: pd.read_sql("""
    WITH cands AS
      (SELECT DISTINCT ON (cand_id) *
       FROM fec_candidates
       WHERE cand_election_yr IN ('2017',
                                  '2018')
         AND cand_pcc IS NOT NULL
       ORDER BY cand_id)
    SELECT cands.*,
           totals.*
    FROM
      (SELECT cand_id,
              sum(CASE WHEN contributor_state != coalesce(cand_office_st,beneficiary_candidate_state) THEN contribution_amount ELSE 0 END) as out_of_state,
              sum(contribution_amount) AS SUM,
              count(*) AS COUNT
       FROM actblue_contribs
       WHERE coalesce(beneficiary_candidate_office,cand_office) IN ('S',
                             'H')
         AND extract(YEAR
                     FROM contribution_date) >= 2017
       GROUP BY cand_id) AS totals
    LEFT JOIN cands USING (cand_id)
    ORDER BY SUM DESC
    """, con=conn)
)
actblue_cand_totals.head(10)
Out[36]:
cand_id cand_name cand_pty_affiliation cand_election_yr cand_office_st cand_office cand_office_district cand_ici cand_status cand_pcc cand_st1 cand_st2 cand_city cand_st cand_zip cand_id out_of_state sum count
0 H2TX16185 O'ROURKE, ROBERT BETO DEM 2018 TX H 16 I C C00501197 1100 LOS ANGELES DRIVE None EL PASO TX 79902 H2TX16185 21,708,404.17 45,412,197.04 1149257
1 H8GA06195 OSSOFF, T. JONATHAN DEM 2017 GA H 06 O C C00630426 PO BOX 450326 None ATLANTA GA 31145 H8GA06195 25,758,014.59 27,468,759.69 1430332
2 S0AL00156 JONES, DOUG DEM 2018 AL S 00 I N C00640623 PO BOX 131025 None BIRMINGHAM AL 35213 S0AL00156 20,314,651.03 22,177,988.84 767342
3 S6MO00305 MCCASKILL, CLAIRE DEM 2018 MO S 00 I F C00431304 PO BOX 300077 None ST LOUIS MO 63130 S6MO00305 9,628,122.18 13,614,383.78 327907
4 S0NY00410 GILLIBRAND, KIRSTEN ELIZABETH DEM 2018 NY S 00 I F C00413914 52 EAST ROAD None BRUNSWICK NY 12180 S0NY00410 6,729,659.18 13,168,962.00 336651
5 S2MA00170 WARREN, ELIZABETH DEM 2018 MA S 00 I F C00500843 None None BOSTON None None S2MA00170 8,101,848.04 10,140,738.44 589348
6 S8FL00166 NELSON, BILL DEM 2018 FL S 00 I F C00344051 10339 KENSINGTON SHORE DRIVE #201 None ORLANDO FL 32827 S8FL00166 3,883,548.78 9,294,124.00 256175
7 S8NV00156 ROSEN, JACKY DEM 2018 NV S 00 C C C00606939 PO BOX 27195 None LAS VEGAS NV 89126 S8NV00156 8,204,086.14 9,213,189.77 215443
8 S2WI00219 BALDWIN, TAMMY DEM 2018 WI S 00 I F C00326801 None None MADISON WI None S2WI00219 4,948,157.61 8,424,141.80 245971
9 S4VT00033 SANDERS, BERNARD IND 2018 VT S 00 I F C00411330 None None BURLINGTON VT None S4VT00033 7,322,971.17 7,535,713.11 351765
In [37]:
actblue_cand_totals.to_csv('data/actblue_cand_totals.csv')

What percentage of ActBlue money was raised from out of state by candidate?

In [38]:
actblue_cand_totals['percent_out'] = actblue_cand_totals['out_of_state']/actblue_cand_totals['sum']

actblue_cand_totals[actblue_cand_totals['sum'] > 1000000].sort_values(by='percent_out',ascending=False).head(100)
Out[38]:
cand_id cand_name cand_pty_affiliation cand_election_yr cand_office_st cand_office cand_office_district cand_ici cand_status cand_pcc cand_st1 cand_st2 cand_city cand_st cand_zip cand_id out_of_state sum count percent_out
9 S4VT00033 SANDERS, BERNARD IND 2018 VT S 00 I F C00411330 None None BURLINGTON VT None S4VT00033 7,322,971.17 7,535,713.11 351765 0.97
84 H8NH01186 SULLIVAN, MAURA CORBY DEM 2018 NH H 01 O C C00658724 PO BOX 1114 None PORTSMOUTH KY 03802 H8NH01186 1,386,891.59 1,438,443.99 3524 0.96
92 H8WI01131 MYERS, CATHY DEM 2018 WI H 01 O C C00648907 PO BOX 2274 None JANESVILLE WI 53545 H8WI01131 1,215,811.73 1,288,760.51 61332 0.94
1 H8GA06195 OSSOFF, T. JONATHAN DEM 2017 GA H 06 O C C00630426 PO BOX 450326 None ATLANTA GA 31145 H8GA06195 25,758,014.59 27,468,759.69 1430332 0.94
52 S0WV00090 MANCHIN III, JOE DEM 2018 WV S 00 I F C00486563 1668 FAIRMONT AVENUE None FAIRMONT WV 26554 S0WV00090 2,019,864.75 2,160,800.02 14092 0.93
19 S2ND00099 HEITKAMP, HEIDI DEM 2018 ND S 00 I F C00505552 21 CAPTAIN LEACH DRIVE None MANDAN ND 58554 S2ND00099 5,395,195.31 5,778,155.37 104779 0.93
61 H6GA05217 LEWIS, JOHN R. DEM 2018 GA H 05 I C C00202416 2015 WALLACE RD. None ATLANTA GA 30331 H6GA05217 1,837,197.11 1,988,061.01 164319 0.92
2 S0AL00156 JONES, DOUG DEM 2018 AL S 00 I N C00640623 PO BOX 131025 None BIRMINGHAM AL 35213 S0AL00156 20,314,651.03 22,177,988.84 767342 0.92
20 H8WI01123 BRYCE, RANDY DEM 2018 WI H 01 O C C00647537 4940 CHESTER LANE #7 None RACINE WI 53402 H8WI01123 4,827,561.25 5,319,862.33 252428 0.91
103 H8VA10122 FRIEDMAN, ALISON DEM 2018 VA H 10 C C C00647024 700 13TH STREET, NW SUITE 600 WASHINGTON DC 20005 H8VA10122 1,031,803.11 1,143,971.24 2714 0.90
7 S8NV00156 ROSEN, JACKY DEM 2018 NV S 00 C C C00606939 PO BOX 27195 None LAS VEGAS NV 89126 S8NV00156 8,204,086.14 9,213,189.77 215443 0.89
101 H8WV03048 OJEDA, RICHARD NEECE SENATOR II DEM 2018 WV H 03 O C C00639989 533 BUNGALOW WOODS DRIVE None HOLDEN WV 25625 H8WV03048 1,034,250.55 1,171,838.17 12532 0.88
78 H8OH07123 HARBAUGH, KENNETH DEM 2018 OH H 07 C C C00646752 PO BOX 338 None AVON OH 44011 H8OH07123 1,361,150.83 1,543,843.85 9924 0.88
16 H8OH12297 O'CONNOR, DANIEL JAY DEM 2018 OH H 12 O C C00667964 464 NORTHRIDGE ROAD None COLUMBUS OH 43214 H8OH12297 5,232,366.68 6,061,801.24 322988 0.86
69 H8IA01094 FINKENAUER, ABBY DEM 2018 IA H 01 C C C00637074 P.O. BOX 598 None DUBUQUE IA 52004 H8IA01094 1,496,633.98 1,748,538.88 61740 0.86
18 H8MT00077 QUIST, ROBERT E. DEM 2017 MT H 00 O C C00632232 581 RIVERSIDE ROAD None KALISPELL MT 59901 H8MT00077 4,891,067.56 5,815,577.72 295575 0.84
76 H8MN01279 FEEHAN, DANIEL DFL 2018 MN H 01 O C C00649327 PO BOX 1844 None NORTH MANKATO MN 56002 H8MN01279 1,320,153.77 1,596,299.13 7856 0.83
23 H8KY06164 MCGRATH, AMY DEM 2018 KY H 06 C C C00646745 P.O. BOX 875 None GEORGETOWN KY 40324 H8KY06164 3,514,074.39 4,326,686.54 60765 0.81
60 H8TX23121 JONES, GINA ORTIZ DEM 2018 TX H 23 C C C00652297 PO BOX 769186 SUITE 200 SAN ANTONIO TX 78245 H8TX23121 1,602,700.80 1,995,191.99 33739 0.80
5 S2MA00170 WARREN, ELIZABETH DEM 2018 MA S 00 I F C00500843 None None BOSTON None None S2MA00170 8,101,848.04 10,140,738.44 589348 0.80
117 None None None None None None None None None None None None None None None S8MN00438 796,083.27 1,023,232.96 65818 0.78
30 H8AZ08083 TIPIRNENI, HIRAL DEM 2018 AZ H 08 O C C00649897 PO BOX 8570 None PHONEIZ AZ 85042 H8AZ08083 2,317,304.02 2,991,785.15 159528 0.77
54 H8KS03155 DAVIDS, SHARICE DEM 2018 KS H 03 C C C00670034 5418 CAENEN ST. None SHAWNEE KS 66216 H8KS03155 1,574,443.11 2,042,629.13 73313 0.77
95 H2MA04073 KENNEDY, JOSEPH P III DEM 2018 MA H 04 I C C00512970 PO BOX 590464 None NEWTON MA 02459 H2MA04073 933,618.73 1,217,133.37 66445 0.77
46 H8FL18028 BAER, LAUREN DEM 2018 FL H 18 C C C00652594 PMB 104-211 6231 PGA BLVD., STE 104-211 PALM BEACH GARDENS FL 33418 H8FL18028 1,744,176.76 2,295,144.28 22994 0.76
13 H8PA18181 LAMB, CONOR DEM 2018 PA H 17 I C C00657411 928 WASHINGTON RD None PITTSBURGH PA 15228 H8PA18181 4,897,359.99 6,469,653.12 214892 0.76
59 H8MI08102 SLOTKIN, ELISSA DEM 2018 MI H 08 C C C00650150 PO BOX 244 None HOLLY MI 48442 H8MI08102 1,493,063.27 1,999,816.39 21348 0.75
62 H8IA03124 AXNE, CINDY DEM 2018 IA H 03 C C C00646844 3775 EP TRUE PARKWAY P.O. BOX 126 WEST DES MOINES IA 50265 H8IA03124 1,447,431.15 1,966,569.01 56843 0.74
72 H8MI11254 STEVENS, HALEY DEM 2018 MI H 11 O C C00638650 33717 WOODWARD AVE #539 BIRMINGHAM MI 48009 H8MI11254 1,269,928.44 1,726,813.71 50796 0.74
21 S6MT00162 TESTER, JON DEM 2018 MT S 00 I C C00412304 709 SON LANE None BIG SANDY MT 59520 S6MT00162 3,833,311.34 5,246,677.28 140980 0.73
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
43 H8NJ11142 SHERRILL, REBECCA MICHELLE DEM 2018 NJ H 11 O C C00640003 176 SOUTH MOUNTAIN AVENUE None MONTCLAIR NJ 07042 H8NJ11142 1,186,801.83 2,317,184.45 63739 0.51
4 S0NY00410 GILLIBRAND, KIRSTEN ELIZABETH DEM 2018 NY S 00 I F C00413914 52 EAST ROAD None BRUNSWICK NY 12180 S0NY00410 6,729,659.18 13,168,962.00 336651 0.51
44 H8IL06139 CASTEN, SEAN DEM 2018 IL H 06 C C C00648493 4915 WOODWARD AVENUE None DOWNERS GROVE IL 60515 H8IL06139 1,177,635.91 2,312,900.15 60681 0.51
32 S8TN00386 BREDESEN, PHILIP DEM 2018 TN S 00 O C C00663658 1724 CHICKERING ROAD None NASHVILLE TN 37215 S8TN00386 1,391,179.37 2,838,619.96 48195 0.49
37 S8MN00578 SMITH, TINA FLINT DEM 2018 MN S 00 I C C00663781 PO BOX 14362 None SAINT PAUL MN 55114 S8MN00578 1,232,282.64 2,517,034.97 44136 0.49
89 H8FL27193 SHALALA, DONNA DEM 2018 FL H 27 O C C00672311 PO BOX 330602 None MIAMI FL 33233 H8FL27193 664,151.59 1,364,250.99 5945 0.49
10 S2CT00132 MURPHY, CHRISTOPHER S MR DEM 2018 CT S 00 I C C00492645 PO BOX 127 None CHESHIRE CT 06410 S2CT00132 3,411,006.37 7,022,947.51 201098 0.49
0 H2TX16185 O'ROURKE, ROBERT BETO DEM 2018 TX H 16 I C C00501197 1100 LOS ANGELES DRIVE None EL PASO TX 79902 H2TX16185 21,708,404.17 45,412,197.04 1149257 0.48
65 None None None None None None None None None None None None None None None S8OR00207 837,379.90 1,821,401.40 128881 0.46
91 H6WA07458 JAYAPAL, PRAMILA DEM 2018 WA H 07 I C C00605592 3826 SOUTH LUCILE STREET None SEATTLE WA 98118 H6WA07458 574,659.21 1,292,576.29 31509 0.44
55 S8WA00194 CANTWELL, MARIA DEM 2018 WA S 00 I F C00349506 PO BOX 12740 None SEATTLE WA 98111 S8WA00194 881,131.67 2,041,801.24 54792 0.43
67 H8TX07140 FLETCHER, ELIZABETH DEM 2018 TX H 07 C C C00640045 3262 WESTHEIMER RD #636 HOUSTON TX 77098 H8TX07140 756,426.23 1,768,056.88 51080 0.43
36 H8TX32098 ALLRED, COLIN DEM 2018 TX H 32 C C C00637868 PO BOX 601631 None DALLAS TX 75360 H8TX32098 1,065,037.78 2,520,053.20 59681 0.42
6 S8FL00166 NELSON, BILL DEM 2018 FL S 00 I F C00344051 10339 KENSINGTON SHORE DRIVE #201 None ORLANDO FL 32827 S8FL00166 3,883,548.78 9,294,124.00 256175 0.42
56 H8NC09123 MCCREADY, DANIEL DEM 2018 NC H 09 C C C00641381 PO BOX 78855 None CHARLOTTE NC 282779770 H8NC09123 839,278.45 2,023,261.31 12022 0.41
57 H8MA03072 KOH, DANIEL ARRIGG DEM 2018 MA H 03 O C C00654509 P.O. BOX 723 None ANDOVER MA 01810 H8MA03072 834,445.89 2,013,526.52 4449 0.41
17 S6PA00217 CASEY, ROBERT P JR DEM 2018 PA S 00 I F C00431056 PO BOX 58746 None PHILADELPHIA PA 19102 S6PA00217 2,463,956.57 6,059,819.92 139241 0.41
15 H8CA22139 JANZ, ANDREW DEM 2018 CA H 22 C C C00638510 16633 VENTURA BLVD., #1008 None ENCINO CA 91436 H8CA22139 2,518,420.31 6,205,223.06 181522 0.41
14 None None None None None None None None None None None None None None None S6CA00584 2,469,149.29 6,467,355.95 375217 0.38
70 H8NY11113 ROSE, MAX DEM 2018 NY H 11 C C C00652248 PO BOX 100496 None STATEN ISLAND NY 10310 H8NY11113 661,297.74 1,736,174.50 11742 0.38
33 H8NY19181 DELGADO, ANTONIO DEM 2018 NY H 19 C C C00633859 PO BOX 802 None RHINEBECK NY 12572 H8NY19181 995,027.49 2,656,776.81 23857 0.37
68 H8OH01118 PUREVAL, AFTAB DEM 2018 OH H 01 C C C00667519 PO BOX 713 None CINCINNATI OH 45201 H8OH01118 659,256.12 1,767,070.68 24863 0.37
24 S2VA00142 KAINE, TIMOTHY MICHAEL DEM 2018 VA S 00 I C C00495358 PO BOX 12307 None RICHMOND VA 23241 S2VA00142 1,582,104.42 4,322,618.00 87587 0.37
75 H8TX21190 KOPSER, JOSEPH DEM 2018 TX H 21 O C C00641191 PO BOX 701711 None SAN ANTONIO TX 78270 H8TX21190 584,204.09 1,614,340.85 12250 0.36
45 H8VA10106 WEXTON, JENNIFER DEM 2018 VA H 10 C C C00638023 PO BOX 650550 None STERLING VA 20165 H8VA10106 824,032.74 2,301,230.15 26505 0.36
73 H8CA50098 CAMPA-NAJJAR, AMMAR DEM 2018 CA H 50 C C C00635888 PO BOX 610 13961 CAMPO ROAD None JAMUL CA 91935 H8CA50098 616,066.18 1,721,920.49 36970 0.36
28 H8CA45130 PORTER, KATHERINE DEM 2018 CA H 45 C C C00636571 777 S. FIGUEROA ST., SUITE 4050 None LOS ANGELES CA 90017 H8CA45130 1,051,602.60 3,099,362.78 99863 0.34
109 H2CA31125 AGUILAR, PETE DEM 2018 CA H 31 I C C00510461 PO BOX 10954 None SAN BERNARDINO CA 92423 H2CA31125 361,862.69 1,089,834.99 56405 0.33
98 H2CA36439 RUIZ, RAUL DR DEM 2018 CA H 36 I C C00502575 77933 LAS MONTANAS RD APT 103 PALM DESERT CA 92211 H2CA36439 400,050.91 1,209,569.86 34479 0.33
116 H8SC01116 CUNNINGHAM, JOE DEM 2018 SC H 01 C C C00650507 PO BOX 1431 None JOHNS ISLAND SC 29457 H8SC01116 335,069.59 1,024,446.73 15319 0.33

100 rows × 20 columns

Who raised the most from out of state in absolute terms?

In [39]:
actblue_cand_totals.sort_values(by='out_of_state',ascending=False).head(10)
Out[39]:
cand_id cand_name cand_pty_affiliation cand_election_yr cand_office_st cand_office cand_office_district cand_ici cand_status cand_pcc cand_st1 cand_st2 cand_city cand_st cand_zip cand_id out_of_state sum count percent_out
1 H8GA06195 OSSOFF, T. JONATHAN DEM 2017 GA H 06 O C C00630426 PO BOX 450326 None ATLANTA GA 31145 H8GA06195 25,758,014.59 27,468,759.69 1430332 0.94
0 H2TX16185 O'ROURKE, ROBERT BETO DEM 2018 TX H 16 I C C00501197 1100 LOS ANGELES DRIVE None EL PASO TX 79902 H2TX16185 21,708,404.17 45,412,197.04 1149257 0.48
2 S0AL00156 JONES, DOUG DEM 2018 AL S 00 I N C00640623 PO BOX 131025 None BIRMINGHAM AL 35213 S0AL00156 20,314,651.03 22,177,988.84 767342 0.92
3 S6MO00305 MCCASKILL, CLAIRE DEM 2018 MO S 00 I F C00431304 PO BOX 300077 None ST LOUIS MO 63130 S6MO00305 9,628,122.18 13,614,383.78 327907 0.71
7 S8NV00156 ROSEN, JACKY DEM 2018 NV S 00 C C C00606939 PO BOX 27195 None LAS VEGAS NV 89126 S8NV00156 8,204,086.14 9,213,189.77 215443 0.89
5 S2MA00170 WARREN, ELIZABETH DEM 2018 MA S 00 I F C00500843 None None BOSTON None None S2MA00170 8,101,848.04 10,140,738.44 589348 0.80
9 S4VT00033 SANDERS, BERNARD IND 2018 VT S 00 I F C00411330 None None BURLINGTON VT None S4VT00033 7,322,971.17 7,535,713.11 351765 0.97
4 S0NY00410 GILLIBRAND, KIRSTEN ELIZABETH DEM 2018 NY S 00 I F C00413914 52 EAST ROAD None BRUNSWICK NY 12180 S0NY00410 6,729,659.18 13,168,962.00 336651 0.51
19 S2ND00099 HEITKAMP, HEIDI DEM 2018 ND S 00 I F C00505552 21 CAPTAIN LEACH DRIVE None MANDAN ND 58554 S2ND00099 5,395,195.31 5,778,155.37 104779 0.93
16 H8OH12297 O'CONNOR, DANIEL JAY DEM 2018 OH H 12 O C C00667964 464 NORTHRIDGE ROAD None COLUMBUS OH 43214 H8OH12297 5,232,366.68 6,061,801.24 322988 0.86

Which states did contributions from come from for each candidate state?

In [40]:
actblue_states = read_or_save(
    'actblue_states',
    lambda: pd.read_sql("""
    SELECT contributor_state,
           coalesce(cand_office_st,beneficiary_candidate_state) as recipient_state,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE extract(YEAR FROM contribution_date) >= 2017
    and coalesce(beneficiary_candidate_office,cand_office) in ('H','S')
    GROUP BY coalesce(cand_office_st,beneficiary_candidate_state),
             contributor_state
    """, con=conn)
)

actblue_states.sort_values(by=['sum'], ascending=False).head(10)
Out[40]:
contributor_state recipient_state count sum
274 CA CA 896949 42,850,038.61
2868 TX TX 672202 34,639,923.20
2272 NY NY 254181 18,854,098.10
570 FL FL 235019 13,276,117.11
2543 PA PA 149550 9,325,733.62
3044 VA VA 128791 8,868,954.94
2815 CA TX 204623 8,618,326.91
1226 MA MA 128435 7,490,243.14
908 IL IL 126602 7,291,670.59
637 CA GA 349317 6,979,157.07
In [41]:
actblue_states.to_csv('data/actblue_states.csv')

Spreadsheet: actblue_states.csv

What percentage of the individual contributions to congressional candidates came from each state in this cycle?

Jan. 1, 2017 — Sept. 30, 2018

In [42]:
actblue_contributor_states = actblue_states.groupby(actblue_states['contributor_state']).agg({'sum': 'sum'})

actblue_contributor_states['percent'] = actblue_contributor_states['sum']/actblue_contributor_states['sum'].sum()*100

actblue_contributor_states.sort_values(by=['percent'], ascending=False).head(10)
Out[42]:
sum percent
contributor_state
CA 119,525,533.58 21.20
NY 67,761,383.71 12.02
TX 45,639,775.40 8.10
MA 29,502,731.70 5.23
FL 24,828,893.70 4.40
IL 20,458,924.49 3.63
WA 18,600,021.86 3.30
VA 18,168,688.10 3.22
PA 16,644,064.84 2.95
DC 15,599,028.00 2.77

What percentage from California and New York?

In [43]:
actblue_contributor_states[actblue_contributor_states.index.isin(['CA','NY'])]['percent'].sum()
Out[43]:
33.22624048868204
In [44]:
actblue_contributor_states.to_csv('data/actblue_contributor_states.csv')

To which states do individual contributions to congressional candidates go?

Jan. 1, 2017 — Sept. 30, 2018

In [45]:
actblue_recipient_states = actblue_states.groupby(actblue_states['recipient_state']).agg({'sum': 'sum'})

actblue_recipient_states['percent'] = actblue_recipient_states['sum']/actblue_recipient_states['sum'].sum()*100

actblue_recipient_states.sort_values(by=['percent'], ascending=False)
Out[45]:
sum percent
recipient_state
TX 65,251,838.19 11.58
CA 62,187,453.75 11.03
NY 33,020,218.03 5.86
GA 32,434,425.86 5.75
FL 25,417,373.69 4.51
AL 22,589,646.44 4.01
PA 21,948,737.22 3.89
MA 20,046,358.31 3.56
OH 19,201,062.97 3.41
VA 18,631,987.47 3.31
WI 16,542,680.99 2.93
MO 15,416,636.95 2.73
IL 15,206,960.89 2.70
AZ 14,897,634.97 2.64
MN 14,592,749.85 2.59
NJ 14,272,724.57 2.53
MT 13,864,932.28 2.46
MI 13,604,064.92 2.41
NV 12,604,235.52 2.24
CT 9,343,316.66 1.66
WA 9,266,908.42 1.64
VT 7,584,410.18 1.35
IN 6,856,782.69 1.22
IA 6,240,235.92 1.11
NM 6,189,320.13 1.10
ND 6,158,619.86 1.09
KS 5,455,123.78 0.97
KY 5,023,464.05 0.89
NC 4,855,332.28 0.86
NH 4,429,768.36 0.79
CO 4,403,763.43 0.78
TN 4,075,768.78 0.72
WV 3,940,068.19 0.70
MD 3,772,491.41 0.67
OR 3,707,704.44 0.66
ME 3,437,878.20 0.61
SC 2,581,448.73 0.46
HI 2,417,458.23 0.43
NE 2,243,135.29 0.40
RI 2,200,644.97 0.39
UT 1,858,157.02 0.33
MS 1,287,297.91 0.23
AR 1,151,349.10 0.20
DE 1,065,884.60 0.19
OK 552,118.50 0.10
AK 525,385.44 0.09
US 451,860.71 0.08
WY 427,908.49 0.08
LA 313,057.55 0.06
DC 65,776.47 0.01
VI 37,905.00 0.01
SD 20,031.35 0.00
ID 10,925.80 0.00
8M 1,699.00 0.00
MP 307.40 0.00

Where is the money going? Are people giving to local congressional candidates or are they giving to candidates around the country?

Jan. 1, 2017 — Sept. 30, 2018

How much ActBlue money came in vs. out of state?

In [46]:
actblue_states['in'] = actblue_states['contributor_state'] == actblue_states['recipient_state']

actblue_states.groupby(actblue_states['in'])['sum'].sum()
Out[46]:
in
False   323,422,085.36
True    240,262,945.85
Name: sum, dtype: float64

What percentage of ActBlue money to congressional candidates came from out of state?

In [47]:
actblue_states[actblue_states['in'] == False]['sum'].sum()/actblue_states['sum'].sum()*100
Out[47]:
57.376383521440275

What about Beto O'Rourke?

How much of the money Beto raised from ActBlue was in state vs. out of state?

In [48]:
actblue_states_beto = read_or_save(
    'actblue_states_beto',
    lambda: pd.read_sql("""
    SELECT contributor_state,
           coalesce(cand_office_st,beneficiary_candidate_state) as recipient_state,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE extract(YEAR FROM contribution_date) >= 2017
    AND beneficiary_committee_fec_id = 'C00501197'
    GROUP BY coalesce(cand_office_st,beneficiary_candidate_state),
             contributor_state
    """, con=conn)
)

actblue_states_beto['in'] = actblue_states_beto['contributor_state'] == actblue_states_beto['recipient_state']

actblue_states_beto.groupby(actblue_states_beto['in'])['sum'].sum()
Out[48]:
in
False   21,709,219.67
True    23,702,977.37
Name: sum, dtype: float64

Where did his ActBlue money come from?

In [49]:
actblue_states_beto.sort_values(by='sum', ascending=False).head(10)
Out[49]:
contributor_state recipient_state count sum in
62 TX TX 567347 23,702,977.37 True
10 CA TX 139569 5,994,453.25 False
48 NY TX 64175 2,957,447.29 False
27 MA TX 31035 1,382,232.81 False
69 WA TX 28873 1,133,803.36 False
22 IL TX 23981 821,914.06 False
15 FL TX 25153 794,133.69 False
29 MD TX 16040 680,621.99 False
13 DC TX 10601 665,396.76 False
65 VA TX 16670 636,415.26 False

What percentage of Beto's ActBlue money came from out of state?

In [50]:
actblue_states_beto[actblue_states_beto['in'] == False]['sum'].sum()/actblue_states_beto['sum'].sum()*100
Out[50]:
47.80482135862766

What about McGrath?

How much of the money Amy McGrath raised from ActBlue was in state vs. out of state?

In [51]:
actblue_states_mcgrath = read_or_save(
    'actblue_states_mcgrath',
    lambda: pd.read_sql("""
    SELECT contributor_state,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE extract(YEAR FROM contribution_date) >= 2017
    AND beneficiary_committee_fec_id = 'C00646745'
    GROUP BY contributor_state
    """, con=conn)
)

actblue_states_mcgrath['in'] = (actblue_states_mcgrath['contributor_state'] == 'KY')

actblue_states_mcgrath.groupby(actblue_states_mcgrath['in'])['sum'].sum()
Out[51]:
in
False   3,516,129.31
True      810,557.23
Name: sum, dtype: float64

Where did her ActBlue money come from?

In [52]:
actblue_states_mcgrath.sort_values(by='sum', ascending=False).head(10)
Out[52]:
contributor_state count sum in
9 CA 12008 999,594.05 False
22 KY 9840 810,557.23 True
41 NY 5520 574,231.65 False
24 MA 3607 344,869.67 False
12 DC 1262 150,474.59 False
25 MD 1844 132,507.02 False
56 VA 1842 132,227.87 False
59 WA 2359 111,989.28 False
14 FL 1741 102,896.26 False
54 TX 1832 95,847.56 False

Where did McGrath's itemized money come from?

In [53]:
mcgrath_itemized_states = read_or_save(
    'mcgrath_itemized_states',
    lambda: pd.read_sql("""
    SELECT contributor_state,
           count(*) AS COUNT,
           sum(contribution_amount) AS SUM
    FROM fec_contributions
    JOIN fec_amended_filings USING (filing_id)
    WHERE filer_committee_id_number = 'C00646745'
      AND form_type = 'SA11AI'
      AND extract(YEAR
                  FROM contribution_date) >= 2017
      AND (memo_code IS NULL
           OR memo_code != 'X')
    GROUP BY contributor_state
    ORDER BY SUM DESC
    """, con=conn)
)

mcgrath_itemized_states.sort_values(by='sum',ascending=False).head(10)
Out[53]:
contributor_state count sum
0 KY 4384 1,262,798.50
1 CA 1712 858,060.71
2 NY 982 587,326.83
3 MA 673 324,136.15
4 DC 287 151,684.23
5 MD 379 112,253.81
6 VA 370 105,277.67
7 FL 179 101,896.99
8 TX 210 76,048.69
9 WA 264 72,889.90

How much of McGrath's Q3 fundraising haul was from ActBlue?

In [54]:
actblue_mcgrath_q3 = read_or_save(
    'actblue_mcgrath_q3',
    lambda: pd.read_sql("""
    SELECT count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE contribution_date >= '2018-07-01'
    AND contribution_date <= '2018-09-30'
    AND beneficiary_committee_fec_id = 'C00646745'
    """, con=conn)
)

actblue_mcgrath_q3
Out[54]:
count sum
0 26599 2,167,188.56

What portion of Ted Cruz's itemized contribs were from out of state?

In [55]:
cruz_itemized_states = read_or_save(
    'cruz_itemized_states',
    lambda: pd.read_sql("""
    SELECT contributor_state,
           count(*) AS COUNT,
           sum(contribution_amount) AS SUM
    FROM fec_contributions
    JOIN fec_amended_filings USING (filing_id)
    WHERE filer_committee_id_number = 'C00492785'
      AND form_type = 'SA11AI'
      AND extract(YEAR
                  FROM contribution_date) >= 2017
      AND (memo_code IS NULL
           OR memo_code != 'X')
    GROUP BY contributor_state
    ORDER BY SUM DESC
    """, con=conn)
)

cruz_itemized_states['percent'] = cruz_itemized_states['sum']/cruz_itemized_states['sum'].sum()*100

cruz_itemized_states.sort_values(by='sum',ascending=False).head(10)
Out[55]:
contributor_state count sum percent
0 TX 19919 3,976,293.36 64.69
1 CA 2768 355,358.68 5.78
2 FL 1406 241,898.50 3.94
3 NY 879 117,775.00 1.92
4 VA 598 90,899.00 1.48
5 GA 479 85,303.76 1.39
6 AZ 549 72,048.00 1.17
7 IL 528 71,138.00 1.16
8 WA 477 62,498.50 1.02
9 OH 496 61,998.57 1.01

Is money from blue states propping up Dems in red states?

Jan. 1, 2017 — Sept. 30, 2018

In [56]:
pres_votes = pd.read_csv('data/presvotes.csv')

pres_votes['red'] = pres_votes['clinton'] < pres_votes['trump']
pres_votes['blue'] = pres_votes['clinton'] > pres_votes['trump']

# pres_votes
In [57]:
pres_votes
Out[57]:
state trump clinton others total red blue
0 AL 1318255 729547 75570 2123372 True False
1 AK 163387 116454 38767 318608 True False
2 AZ 1252401 1161167 159597 2573165 True False
3 AR 684872 380494 65310 1130676 True False
4 CA 4483814 8753792 943998 14181604 False True
5 CO 1202484 1338870 238893 2780247 False True
6 CT 673215 897572 74133 1644920 False True
7 DE 185127 235603 23084 443814 False True
8 DC 12723 282830 15715 311268 False True
9 FL 4617886 4504975 297178 9420039 True False
10 GA 2089104 1877963 147665 4114732 True False
11 HI 128847 266891 33199 428937 False True
12 ID 409055 189765 91435 690255 True False
13 IL 2146015 3090729 299680 5536424 False True
14 IN 1557286 1033126 144546 2734958 True False
15 IA 800983 653669 111379 1566031 True False
16 KS 671018 427005 86379 1184402 True False
17 KY 1202971 628854 92324 1924149 True False
18 LA 1178638 780154 70240 2029032 True False
19 ME 335593 357735 54599 747927 False True
20 MD 943169 1677928 160349 2781446 False True
21 MA 1090893 1995196 238957 3325046 False True
22 MI 2279543 2268839 250902 4799284 True False
23 MN 1322951 1367716 254146 2944813 False True
24 MS 700714 485131 23512 1209357 True False
25 MO 1594511 1071068 143026 2808605 True False
26 MT 279240 177709 40198 497147 True False
27 NE 495961 284494 63772 844227 True False
28 NV 512058 539260 74067 1125385 False True
29 NH 345790 348526 49980 744296 False True
30 NJ 1601933 2148278 123835 3874046 False True
31 NM 319667 385234 93418 798319 False True
32 NY 2819533 4556118 345791 7721442 False True
33 NC 2362631 2189316 189617 4741564 True False
34 ND 216794 93758 33808 344360 True False
35 OH 2841005 2394164 261318 5496487 True False
36 OK 949136 420375 83481 1452992 True False
37 OR 782403 1002106 216827 2001336 False True
38 PA 2970733 2926441 268304 6165478 True False
39 RI 180543 252525 31076 464144 False True
40 SC 1155389 855373 92265 2103027 True False
41 SD 227721 117458 24914 370093 True False
42 TN 1522925 870695 114407 2508027 True False
43 TX 4685047 3877868 406311 8969226 True False
44 UT 515231 310676 305523 1131430 True False
45 VT 95369 178573 41125 315067 False True
46 VA 1769443 1981473 233715 3984631 False True
47 WA 1221747 1742718 352554 3317019 False True
48 WV 489371 188794 36258 714423 True False
49 WI 1405284 1382536 188330 2976150 True False
50 WY 174419 55973 25457 255849 True False

What's the correlation between 2018 ActBlue dollars per 2016 presidential vote and Clinton margin?

In [58]:
pres_votes['margin'] = (pres_votes['clinton']/pres_votes['total'])-(pres_votes['trump']/pres_votes['total'])

pres_votes_indexed = pres_votes.set_index('state')

votes_vs_contribs = actblue_contributor_states.merge(pres_votes_indexed, left_index=True, right_index=True, how='inner')

votes_vs_contribs['dollars_per'] = votes_vs_contribs['sum']/votes_vs_contribs['total']

votes_vs_contribs[votes_vs_contribs.index != "DC"].plot.scatter(x='margin', y='dollars_per')
Out[58]:
<matplotlib.axes._subplots.AxesSubplot at 0x112dd0320>

What's the average contribution per vote from red states?

In [59]:
votes_vs_contribs[votes_vs_contribs['red']]['sum'].sum()/votes_vs_contribs[votes_vs_contribs['red']]['total'].sum()
Out[59]:
2.386809612065317

What's the average contribution per vote from blue states?

In [60]:
votes_vs_contribs[votes_vs_contribs['blue']]['sum'].sum()/votes_vs_contribs[votes_vs_contribs['blue']]['total'].sum()
Out[60]:
6.350111488017808

What's the average where Clinton won by a lower margin than 20%?

In [61]:
votes_vs_contribs[(votes_vs_contribs['margin'] > 0) & (votes_vs_contribs['margin'] < 0.2)]['sum'].sum()/votes_vs_contribs[(votes_vs_contribs['margin'] > 0) & (votes_vs_contribs['margin'] < 0.2)]['total'].sum()
Out[61]:
4.162720275817787

What's the average where Clinton won by a higher margin than 20%?

In [62]:
votes_vs_contribs[(votes_vs_contribs['margin'] >= 0.2)]['sum'].sum()/votes_vs_contribs[(votes_vs_contribs['margin'] >= 0.2)]['total'].sum()
Out[62]:
8.63853885919089

Which states were those?

In [63]:
votes_vs_contribs[(votes_vs_contribs['margin'] >= 0.2)]
Out[63]:
sum percent trump clinton others total red blue margin dollars_per
CA 119,525,533.58 21.20 4483814 8753792 943998 14181604 False True 0.30 8.43
DC 15,599,028.00 2.77 12723 282830 15715 311268 False True 0.87 50.11
HI 2,125,665.34 0.38 128847 266891 33199 428937 False True 0.32 4.96
MA 29,502,731.70 5.23 1090893 1995196 238957 3325046 False True 0.27 8.87
MD 15,065,546.04 2.67 943169 1677928 160349 2781446 False True 0.26 5.42
NY 67,761,383.71 12.02 2819533 4556118 345791 7721442 False True 0.22 8.78
VT 1,497,602.25 0.27 95369 178573 41125 315067 False True 0.26 4.75
In [64]:
# votes_vs_contribs[votes_vs_contribs['dollars_per'] > 7.5]
In [65]:
# votes_vs_contribs[votes_vs_contribs['dollars_per'] <= 1.3]
In [66]:
# votes_vs_contribs.groupby(votes_vs_contribs['blue'])['sum'].sum()

How much did blue state contributor give to red state candidates and vice versa?

In [67]:
contrib_flow = pres_votes[['state','blue']].merge(pres_votes[['state','blue']].merge(actblue_states, right_on='contributor_state', left_on='state', how='inner'), right_on='recipient_state', left_on='state', how='inner', suffixes=['_recip','_contrib'])

contrib_flow

pd.pivot_table(contrib_flow, values='sum', index=['blue_recip'], columns=['blue_contrib'], aggfunc=np.sum)
Out[67]:
blue_contrib False True
blue_recip
False 156,595,882.21 157,201,060.36
True 27,596,006.96 220,041,691.35

How much flowed from blue states to red states?

In [68]:
contrib_flow[(~contrib_flow['blue_recip']) & (contrib_flow['blue_contrib'])]['sum'].sum()
Out[68]:
157201060.36

How much flowed from red states to blue states?

In [69]:
contrib_flow[(contrib_flow['blue_recip']) & (~contrib_flow['blue_contrib'])]['sum'].sum()
Out[69]:
27596006.96

What's the multiple of one to the other?

In [70]:
contrib_flow[(~contrib_flow['blue_recip']) & (contrib_flow['blue_contrib'])]['sum'].sum()/contrib_flow[(contrib_flow['blue_recip']) & (~contrib_flow['blue_contrib'])]['sum'].sum()
Out[70]:
5.696514738087311

Removing in-state

In [71]:
pd.pivot_table(contrib_flow[~contrib_flow['in']], values='sum', index=['blue_recip'], columns=['blue_contrib'], aggfunc=np.sum)
Out[71]:
blue_contrib False True
blue_recip
False 42,465,918.45 157,201,060.36
True 27,596,006.96 93,924,559.26

Recipient states not in state

In [72]:
actblue_recipient_out_states = actblue_states[~actblue_states['in']].groupby(actblue_states[~actblue_states['in']]['recipient_state']).agg({'sum': 'sum'})

actblue_recipient_out_states['percent'] = actblue_recipient_out_states['sum']/actblue_recipient_out_states['sum'].sum()*100

actblue_recipient_out_states.sort_values(by=['percent'], ascending=False)
Out[72]:
sum percent
recipient_state
TX 30,611,914.99 9.47
GA 29,408,857.87 9.09
AL 20,526,226.16 6.35
CA 19,337,415.14 5.98
NY 14,166,119.93 4.38
PA 12,623,003.60 3.90
MA 12,556,115.17 3.88
OH 12,531,430.09 3.87
FL 12,141,256.58 3.75
WI 11,812,845.55 3.65
NV 10,393,369.87 3.21
MO 10,220,520.74 3.16
MT 10,091,166.81 3.12
VA 9,763,032.53 3.02
AZ 8,870,446.92 2.74
NJ 8,328,848.83 2.58
MN 8,036,707.50 2.48
IL 7,915,290.30 2.45
MI 7,556,384.57 2.34
VT 7,370,306.42 2.28
ND 5,533,394.95 1.71
IA 4,623,073.18 1.43
CT 4,419,421.02 1.37
IN 4,053,621.95 1.25
KY 3,707,346.57 1.15
KS 3,616,494.27 1.12
WV 3,540,324.30 1.09
NM 3,480,255.23 1.08
NH 3,223,535.24 1.00
WA 2,714,502.06 0.84
ME 2,202,153.52 0.68
NC 2,132,144.87 0.66
TN 1,845,071.70 0.57
MD 1,629,451.17 0.50
CO 1,588,501.12 0.49
HI 1,546,158.85 0.48
OR 1,514,056.05 0.47
RI 1,483,422.40 0.46
SC 1,280,087.86 0.40
NE 1,121,354.43 0.35
MS 969,045.26 0.30
DE 630,833.98 0.20
UT 575,249.84 0.18
AR 538,648.53 0.17
US 451,860.71 0.14
WY 239,306.55 0.07
AK 207,780.18 0.06
OK 135,521.62 0.04
LA 90,627.36 0.03
DC 31,385.47 0.01
VI 22,055.00 0.01
SD 6,230.35 0.00
ID 5,903.80 0.00
8M 1,699.00 0.00
MP 307.40 0.00

What about 2014?

In [73]:
actblue_states_14 = read_or_save(
    'actblue_states_14',
    lambda: pd.read_sql("""
    SELECT contributor_state,
           coalesce(cand_office_st,beneficiary_candidate_state) as recipient_state,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE extract(YEAR FROM contribution_date) >= 2013
    and extract(YEAR FROM contribution_date) <= 2014
    and coalesce(beneficiary_candidate_office,cand_office) in ('H','S')
    GROUP BY coalesce(cand_office_st,beneficiary_candidate_state),
             contributor_state
    """, con=conn)
)

actblue_states_14.sort_values(by=['sum'], ascending=False).head(10)
Out[73]:
contributor_state recipient_state count sum
255 CA CA 133376 6,967,833.42
325 CO CO 72559 4,331,550.76
2064 NY NY 65778 3,749,591.77
2705 VA VA 44953 3,524,258.10
820 IL IL 52903 3,371,706.41
517 FL FL 60414 2,764,482.61
1125 MA MA 34224 2,743,338.51
1612 NC NC 42142 2,175,535.46
188 AZ AZ 48553 2,156,247.86
1305 MI MI 31716 1,799,948.21
In [74]:
actblue_states_14['in'] = actblue_states_14['contributor_state'] == actblue_states_14['recipient_state']

contrib_flow_14 = pres_votes[['state','blue']].merge(pres_votes[['state','blue']].merge(actblue_states_14, right_on='contributor_state', left_on='state', how='inner'), right_on='recipient_state', left_on='state', how='inner', suffixes=['_recip','_contrib'])

pd.pivot_table(contrib_flow_14, values='sum', index=['blue_recip'], columns=['blue_contrib'], aggfunc=np.sum)
Out[74]:
blue_contrib False True
blue_recip
False 27,667,379.98 21,801,384.27
True 7,554,302.28 56,554,211.23

Removing in-state

In [75]:
pd.pivot_table(contrib_flow_14[~contrib_flow_14['in']], values='sum', index=['blue_recip'], columns=['blue_contrib'], aggfunc=np.sum)
Out[75]:
blue_contrib False True
blue_recip
False 7,481,729.62 21,801,384.27
True 7,554,302.28 23,523,012.88

What percent of Clinton votes from California and New York?

How many from California and New York?

In [76]:
pres_votes[(pres_votes['state'] == 'CA') | (pres_votes['state'] == 'NY')]
Out[76]:
state trump clinton others total red blue margin
4 CA 4483814 8753792 943998 14181604 False True 0.30
32 NY 2819533 4556118 345791 7721442 False True 0.22
In [77]:
pres_votes['clinton'].sum()
Out[77]:
65853514

What percentage of Clinton votes were from those two states?

In [78]:
(pres_votes[pres_votes['state'] == 'CA']['clinton'].sum()+pres_votes[pres_votes['state'] == 'NY']['clinton'].sum())/pres_votes['clinton'].sum()*100
Out[78]:
20.211389175071204

What about Texas? Which cities gave?

In [79]:
actblue_texas_cities = read_or_save(
    'actblue_texas_cities',
    lambda: pd.read_sql("""
    SELECT lower(contributor_city),
           count(*) AS COUNT,
           sum(contribution_amount) AS SUM
    FROM actblue_contribs
    WHERE contributor_state = 'TX'
      AND extract(YEAR
                  FROM contribution_date) > 2017
      AND coalesce(beneficiary_candidate_office,cand_office) IN ('H','S')
    GROUP BY lower(contributor_city)
    ORDER BY COUNT DESC
    """, con=conn)
)

actblue_texas_cities['percent'] = actblue_texas_cities['sum']/actblue_texas_cities['sum'].sum()*100

actblue_texas_cities.head(5)
Out[79]:
lower count sum percent
0 austin 137366 6,693,561.19 19.42
1 houston 92609 6,809,717.84 19.75
2 dallas 64514 4,671,169.01 13.55
3 san antonio 43410 1,695,909.08 4.92
4 fort worth 21909 792,488.26 2.30

What percentage came from the top three Texas cities?

In [80]:
actblue_texas_cities[actblue_texas_cities['lower'].isin(['austin','houston','dallas'])]['percent'].sum()
Out[80]:
52.72131445051973

What does this look like for special election candidates running in 2018?

In [81]:
specials = ['C00631564',
            'C00634543',
            'C00662650',
            'C00615823',
            'C00656116',
            'C00663161',
            'C00655332',
            'C00647339',
            'C00680348',
            'C00632067',
            'C00631945',
            'C00629659',
            'C00633362',
            'C00641340',
            'C00640623',
            'C00657411',
            'C00663914',
            'C00655977',
            'C00639401',
            'C00633610',
            'C00667964',
            'C00630426',
            'C00634709',
            'C00680942',
            'C00632232',
            'C00658708',
            'C00678672',
            'C00649897',
            'C00660142',
            'C00679779',
            'C00647917',
            'C00635128']

actblue_specials = actblue_proportion_amount[actblue_proportion_amount['cand_pcc'].isin(specials)].merge(actblue_transfers, left_on='cand_pcc', right_on='beneficiary_committee_fec_id', how='inner')[['cand_pcc','name','committee_total','actblue_total']]
In [82]:
actblue_specials[['committee_total','actblue_total']].sum()
Out[82]:
committee_total   82,121,621.48
actblue_total     72,978,917.38
dtype: float64

Do the majority of these donors give repeatedly or are they one and done? How “sticky” is this? What percentage of donors gave how many times?

Jan. 1, 2013 — Sept. 30, 2018

In [83]:
actblue_freq = read_or_save(
    'actblue_freq',
    lambda: pd.read_sql("""
    SELECT COUNT,
           count(*) AS count_of_count
    FROM
      (SELECT contributor_first_name,
              contributor_last_name,
              left(contributor_zip_code,5),
              count(DISTINCT contribution_date::text || contribution_amount) AS COUNT
       FROM actblue_contribs
       WHERE extract(year from contribution_date) >= 2017
       GROUP BY contributor_first_name,
                contributor_last_name,
                left(contributor_zip_code,5)) AS donors
    GROUP BY COUNT
    """, con=conn)
)

actblue_freq['percent'] = actblue_freq['count_of_count']/actblue_freq['count_of_count'].sum()*100

actblue_freq.sort_values(by=['count_of_count'], ascending=False).head(5)
Out[83]:
count count_of_count percent
1007 1 1240596 34.74
102 2 738666 20.69
213 3 276326 7.74
632 4 225961 6.33
356 5 127387 3.57
In [84]:
actblue_freq.to_csv('data/actblue_freq.csv')

Spreadsheet: actblue_freq.csv

ActBlue addicts: Do certain donors give a lot through ActBlue?

Jan. 1, 2017 — Sept. 30, 2018

In [85]:
actblue_addicts = read_or_save(
    'actblue_addicts',
    lambda: pd.read_sql("""
    SELECT contributor_first_name,
           contributor_last_name,
           array_agg(DISTINCT contributor_occupation),
           array_agg(DISTINCT contributor_employer),
           array_agg(DISTINCT contributor_street_1),
           array_agg(DISTINCT contributor_city),
           contributor_state,
           left(contributor_zip_code,5) AS contributor_zip_code,
           count(DISTINCT contribution_date::text || contribution_amount) AS COUNT,
           sum(contribution_amount) AS total,
           sum(contribution_amount)/count(DISTINCT contribution_date::text || contribution_amount) AS avg_per
    FROM actblue_contribs
    WHERE extract(YEAR
                  FROM contribution_date) > 2016
    GROUP BY contributor_first_name,
             contributor_last_name,
             contributor_state,
             left(contributor_zip_code,5)
    ORDER BY COUNT DESC
    LIMIT 100
    """, con=conn)
)
actblue_addicts
Out[85]:
contributor_first_name contributor_last_name array_agg array_agg array_agg array_agg contributor_state contributor_zip_code count total avg_per
0 SIBYLLE BARLOW [RETIRED] [RETIRED] [241 HOLDEN WOOD ROAD] [CONCORD] MA 01742 4877 67,973.95 13.94
1 VICKI FARRAR [NOT EMPLOYED] [NOT EMPLOYED] [P O BOX 140375] [GARDEN CITY] ID 83714 4154 37,014.92 8.91
2 MONIQUE WEIL [RETIRED] [NONE] [6022 MERRIEWOOD DR] [OAKLAND] CA 94611 3844 55,854.87 14.53
3 ROXANNE WARREN [ARCHITECT, ARCHITECTS] [SELF] [523 WEST 112TH STREET 72] [NEW YORK] NY 10025 3394 96,462.68 28.42
4 JAN GARRETT [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [2108 MCCUBBIN DR, 218 MCCUBBIN DR] [BOWLING GREEN] KY 42104 3191 20,348.06 6.38
5 CAROLINE MERRIAM [FOUNDATION PRESIDENT] [RAMSAY MERRIAM FUND] [1316 30TH STREET NW] [WASHINGTON] DC 20007 3004 125,572.80 41.80
6 RICHARD GOLDSTEIN [NOT EMPLOYED, RETIRED] [NOT EMPLOYED, RETIRED] [375 SAGAPONACK RD, L O BOX752, P O 752, POB0X... [SAFAPONACK, SAGAPONACK] NY 11962 2861 146,650.73 51.26
7 VIRGINIA SMITH [NONE, NOT EMPLOYED, RETIRED] [NONE, NOT EMPLOYED, RETIRED] [130 BULMER DRIVE, 130BULMER DRIVE, 130 NULMER... [STRATFORD] CT 06614 2845 85,852.79 30.18
8 THOMAS RE' [ENTREPRENEUR] [SELF] [661 BLANDFORD ROAD] [GRANVILLE] MA 01034 2817 29,391.08 10.43
9 GARLAND RIGGS [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [8603 NIGHTINGALE DR ] [LANHAM] MD 20706 2668 22,681.83 8.50
10 BRENDA TROUP [NONE] [NONE] [21 MEADOW ROAD] [BOLTON] MA 01740 2657 23,249.87 8.75
11 TOM BROWNSCOMBE [NOT EMPLOYED] [NOT EMPLOYED] [3019 TANGEY, 3019 TANGLEY, 3019 TANGLEY ROAD] [HOUSTON] TX 77005 2614 47,833.06 18.30
12 JUDITH HUNT [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [513 YELLOWSTONE CT, 513 YELLOWSTONE CT ] [PETALUMA] CA 94954 2570 38,378.62 14.93
13 WILLIAM CHEEK [RETIRED PROFESSOR] [NONE] [6209 ESTELLE ST] [SAN DIEGO] CA 92115 2568 88,468.61 34.45
14 EDITH ALLEN [ECONOMIST (RETIRED)] [NONE] [83 LINCOLN AVENUE 2] [ALBANY] NY 12206 2540 18,474.99 7.27
15 WENDY TSIEN [NONE] [NONE] [85200 RIDGETOP DRIVE] [EUGENE] OR 97405 2395 57,838.56 24.15
16 ELIZABETH M. POSTELL [NONE] [NONE] [425 DAVIS ST UNIT 909] [EVANSTON] IL 60201 2296 61,851.50 26.94
17 CLAUDIA PALMER [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [15 GORHAM ROAD] [SCARSDALE] NY 10583 2237 34,337.22 15.35
18 CHARLES FAVREAU [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [20 CONTINENTAL AVE, 20 CONTINENTAL AVENUE] [FOREST HILLS, QUEENS] NY 11375 2228 24,705.00 11.09
19 CLAUDIA BUDGE [NOT EMPLOYED] [NONE] [2 LYFORD DRIVE 6] [TIBURON] CA 94920 2224 17,082.78 7.68
20 PATRICIA WALKER [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [3868 POTOMAC AV ] [DALLAS] TX 75205 2218 322,887.47 145.58
21 ROBERT ECKEL [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [331 L DOLINGTON RD APT R2, 331LOWERDOLINGT N ... [NEWTOWN] PA 18940 2212 19,833.66 8.97
22 PIERRE PIPER [NOT EMPLOYED] [NOT EMPLOYED] [8792 BRUNELL WAY] [INVER GROVE HEIGHT] MN 55076 2163 31,057.99 14.36
23 SONIA IMMASCHE [NONE, NOT EMPLOYED, RETIRED] [NONE, NOT EMPLOYED, RETIRED] [730 COTTONWOOD DRIVE] [FORT COLLINS] CO 80524 2120 16,423.02 7.75
24 CHARLES Y WRIGLEY [CEO, PRESIDENT] [LUMITEK INTERNATIONAL, INC.] [2732 HILLSIDE COURT] [IJAMSVILLE] MD 21754 2103 16,559.56 7.87
25 SAMUEL BRADLEY [NONE] [NONE] [4824 27TH PLL N] [ARLINGTON] VA 22207 2075 27,972.25 13.48
26 CATHERINE BOYAN [NOT EMPLOYED] [NONE, NOT EMPLOYED] [4 S COVE RD] [BURLINGTON] VT 05401 2065 56,162.46 27.20
27 LINDA KOHN [NURSE PRACTITIONER] [WHITFORD FAMILY MEDICINE] [PO BOX 655, POBOX 655] [DEVAULT] PA 19432 1977 13,463.43 6.81
28 LUCY HARMON [NOT EMPLOYED] [SELF] [13621SHANNON ST] [LINDALE] TX 75771 1974 65,058.73 32.96
29 DENNIS MCPHERSON [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [128 NW WHITMAN DRIVE] [LEES SUMMIT] MO 64081 1967 13,392.20 6.81
... ... ... ... ... ... ... ... ... ... ... ...
70 ELLEN TAYLOR [RETIRED] [NONE] [5381 ASPENWOOD COURT, 5381ASPENWOOD CT] [CONCORD] CA 94521 1550 9,451.86 6.10
71 BEN RUBINROI [ACCOUNTAINT] [SELF] [739 DUMONT PL] [VALLEY] NY 11581 1530 1,606.78 1.05
72 BEVERLY MULLINEAUX [NOT EMPLOYED] [NOT EMPLOYED] [602 N 116TH ST NONE] [WAUWATOSA] WI 53226 1524 29,296.53 19.22
73 SARAH WEATHERSBY [NONE, NOT EMPLOYED] [NONE, NOT EMPLOYED] [700 QUIET WALK CIRCLE, PO BOX 548] [ROLESVILLE] NC 27571 1521 19,286.11 12.68
74 ROBERTA CAMP [NOT EMPLOYED] [NOT EMPLOYED] [713 SOUTH WARNOCK STREET, 713 S WARNOCK ST ] [PHILADELPHIA] PA 19147 1519 8,584.61 5.65
75 JOHN COMELLA [NONE] [NONE] [1900 J F KENNEDY BLVD SUITE 1624] [PHILADELPHIA] PA 19103 1512 35,048.60 23.18
76 KARL ANDERSON [NOT EMPLOYED] [NOT EMPLOYED] [6733 N ASHLAND] [CHICAGO] IL 60626 1498 26,026.75 17.37
77 DAVID COLES [PROFESSOR OF HISTORY AND THEOLOGY] [CONCORDIA THEOLOGICAL SEMINARY] [5414-C RIVER RUN TRAIL] [FORT WAYNE] IN 46825 1497 130,395.10 87.10
78 JANE WHEELER [NOT EMPLOYED, RETIRED] [NOT EMPLOYED] [15 HAMILTON ROAD] [HOPEWELL JUNCTION] NY 12533 1493 24,920.45 16.69
79 JONATHAN WEINSTOCK [PROGRAM MANAGER] [EDGEWOOD] [1846B PAGE ST] [SAN FRANCISCO] CA 94117 1493 13,580.55 9.10
80 MICHAEL AARSVOLD [ARTIST] [ELECTRONIC ARTS] [4550 W 153RD PLACE] [LAWNDALE] CA 90260 1484 5,548.11 3.74
81 LARRY AUERBACH [PROFESSOR] [UNIVERSITY SOUTHERN CALIFORNIA, UNIV SOUTHERN... [1040 COVE WAY] [BEVERLY HILLS] CA 90210 1478 19,541.78 13.22
82 JOYCE THIBODEAUX [NOT EMPLOYED] [NONE] [113 OAKDALE LOOP] [HOUMA] LA 70360 1478 91,449.25 61.87
83 JOYCE ABRAMS [RANCHER/WRITER] [SELF] [5489 TAKILMA ROAD CAVE JUNCTION] [CAVE JUNCTION] OR 97523 1473 17,767.18 12.06
84 ROTRAUD COFFEY [NOT EMPLOYED] [NONE, NOT EMPLOYED] [3304 OAKELLAR AVE, 3304 W OAKELLAR AVE] [TAMPA] FL 33611 1469 6,202.65 4.22
85 EILEEN LAWRENCE [NOT EMPLOYED, RETIRED] [NOT EMPLOYED, RETIRED] [44-30 DOUGLASTON PKWY, 4430 DOUGLASTON PKWY] [LITTLE NECK] NY 11363 1454 21,409.36 14.72
86 MIRIAM CASTELLANOS [RDA] [GROSSMAN AND MCKAY DENTAL] [2875 GRACELAND WAY] [GLENDALE] CA 91206 1444 9,354.60 6.48
87 CHRISTINA EINSTEIN [NOT EMPLOYED, RETIRED] [NONE, NOT EMPLOYED] [3401 CHRIS LANE] [SAN MATEO] CA 94403 1440 18,057.56 12.54
88 HERMAN WHITERABBIT [FINISHER] [BOB'S COPY SHOP] [481 MARIGOLD DRIVE] [MADISON] WI 53713 1437 4,540.05 3.16
89 PATRICIA GOUGHAN [NOT EMPLOYED] [NOT EMPLOYED] [951 14TH STREET] [PACIFIC GROVE] CA 93950 1433 57,988.47 40.47
90 SUZIE RHEA HAUGHN [NONE, RETIRED] [NONE, RETIRED] [1725PO, 1725 SUN CITY AZ 85372, PO 1725] [SUN CITY] AZ 85372 1422 13,194.66 9.28
91 CHARLES W BAUMANN [NOT EMPLOYED] [NONE] [949 S BATAVIA AVE] [GENEVA] IL 60134 1410 10,657.70 7.56
92 JANET BULLOCK [CEO, PRESIDENT] [INNOVATIVE LEARNING CONCEPTS, INNOVATIVE LEAR... [9 ALTA VISTA ROAD, 9ALTA VISTA ROAD] [COLORADO SPRINGS] CO 80906 1409 81,360.44 57.74
93 LEE JAMES SHARP [RETIRED] [NONE] [644 MAINSAIL PLACE] [NAPLES] FL 34110 1390 12,068.30 8.68
94 PRISCILLA GILMAN [NOT EMPLOYED] [NOT EMPLOYED] [4537 DEER RUN, 4537DEER RUN] [EVANS] GA 30809 1390 51,678.85 37.18
95 TIMOTHY TOMASIK [LIBRARIAN] [SACRAMENTO PUBLIC LIBRARY AUTHORITY] [9128 DUPONT WAY] [SACRAMENTO] CA 95826 1384 9,163.86 6.62
96 WILLIAM BONDINELL [NONE, NOT EMPLOYED, RETIRED] [NONE, NOT EMPLOYED, RETIRED] [1512 FRANKLIN LANE, 1512FRANKLIN LANE, 1522 F... [CHESTERBROOK, WAYNE] PA 19087 1376 36,079.80 26.22
97 JAMES AMORY [NONE] [NONE] [228 SQUIRES AVE R1] [ENDICOTT] NY 13760 1376 15,154.42 11.01
98 JANET FAIRCHILD [ATTORNEY, NONE] [NONE, SELF] [10329 SAN PABLO AVE, 2432 - 10TH ST, 2432 10T... [BERKELEY, EL CERRITO] CA 94710 1368 12,722.34 9.30
99 HILDA BROWN [NOT EMPLOYED] [NOT EMPLOYED] [1032 N HORSEPOUND ROAD, 1032 N HOSEPOUND ROAD... [CARMEL, CARMEL HAMLET] NY 10512 1365 12,201.85 8.94

100 rows × 11 columns

In [86]:
actblue_addicts.to_csv('data/actblue_addicts.csv')

Spreadsheet: actblue_addicts.csv

How did Terry Wolfe give?

In [87]:
actblue_wolfe = read_or_save(
    'actblue_wolfe',
    lambda: pd.read_sql("""
    SELECT contribution_date,
           contribution_amount,
           
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE contributor_last_name = 'WOLFE'
      AND contributor_first_name = 'TERRY'
      AND contributor_zip_code ILIKE '26508%'
      AND coalesce(beneficiary_candidate_office,cand_office) IN ('S',
                          'H')
      AND cand_pty_affiliation IN ('DEM','DFL')
      AND extract(YEAR
                  FROM contribution_date) >= 2017
    GROUP BY contribution_date,
             contribution_amount
    ORDER BY count(*) DESC
    """, con=conn)
)
actblue_wolfe.head(5)
Out[87]:
contribution_date contribution_amount count sum
0 2017-10-03 1.00 55 55.00
1 2017-09-28 1.00 55 55.00
2 2017-11-30 1.00 47 47.00
3 2018-03-31 1.00 46 46.00
4 2018-03-30 1.00 44 44.00

How much did Wolfe give in total to Democrats?

In [88]:
actblue_wolfe['sum'].sum()
Out[88]:
14530.66

What Wolfe's (at most) average contribution?

In [89]:
actblue_wolfe['sum'].mean()
Out[89]:
10.925308270676691

Did he give to non-Democrats?

In [90]:
actblue_wolfe_indies = read_or_save(
    'actblue_wolfe_indies',
    lambda: pd.read_sql("""
    SELECT *
    FROM actblue_contribs
    WHERE contributor_last_name = 'WOLFE'
      AND contributor_first_name = 'TERRY'
      AND contributor_zip_code ILIKE '26508%'
      AND coalesce(beneficiary_candidate_office,cand_office) IN ('S',
                          'H')
      AND cand_pty_affiliation NOT IN ('DEM','DFL')
      AND extract(YEAR
                  FROM contribution_date) >= 2017
    """, con=conn)
)

actblue_wolfe_indies
Out[90]:
filing_id transaction_id contributor_last_name contributor_first_name contributor_street_1 contributor_city contributor_state contributor_zip_code contribution_date contribution_amount ... election_code beneficiary_committee_fec_id beneficiary_candidate_fec_id beneficiary_candidate_state beneficiary_candidate_office cand_id cand_pty_affiliation cand_office_st cand_office cand_pcc
0 1217370 SA11AI_87875771 WOLFE TERRY 1199 E 3RD ST MORGANTOWN WV 265089706 2017-07-28 2.00 ... P2016 C00411330 S4VT00033 VT S S4VT00033 IND VT S C00411330
1 1217370 SA11AI_88116332 WOLFE TERRY 1199 E 3RD ST MORGANTOWN WV 265089706 2017-07-31 1.00 ... P2016 C00411330 S4VT00033 VT S S4VT00033 IND VT S C00411330
2 1219420 SA11AI_92459910 WOLFE TERRY 1199 E 3RD ST MORGANTOWN WV 265089706 2017-10-03 1.00 ... P2016 C00411330 S4VT00033 VT S S4VT00033 IND VT S C00411330
3 1219434 SA11AI_95626237 WOLFE TERRY 1199 E 3RD ST MORGANTOWN WV 265089706 2017-11-13 1.00 ... P2016 C00602920 H6FL23063 FL H H6FL23063 IND FL H C00602920
4 1225971 SA11AI_107101579 WOLFE TERRY 1199 EAST THIRD STREET MORGANTOWN WV 26508 2018-03-27 1.00 ... P2016 C00516047 S2ME00109 ME S S2ME00109 IND ME S C00516047
5 1224416 SA11AI_97631489 WOLFE TERRY 1199 E 3RD ST MORGANTOWN WV 265089706 2017-12-05 1.00 ... P2016 C00411330 S4VT00033 VT S S4VT00033 IND VT S C00411330
6 1215697 SA11AI_102924562 WOLFE TERRY 1199 EAST THIRD STREET MORGANTOWN WV 26508 2018-02-10 1.00 ... P2016 C00602920 H6FL23063 FL H H6FL23063 IND FL H C00602920

7 rows × 23 columns

How much did Wolfe give to Richard Ojeda?

In [91]:
actblue_wolfe_ojeda = read_or_save(
    'actblue_wolfe_ojeda',
    lambda: pd.read_sql("""
    SELECT *
    FROM actblue_contribs
    WHERE contributor_last_name = 'WOLFE'
      AND contributor_first_name = 'TERRY'
      AND contributor_zip_code ILIKE '26508%'
      AND cand_pcc = 'C00639989'
      AND extract(YEAR
                  FROM contribution_date) >= 2017
    """, con=conn)
)
actblue_wolfe_ojeda['contribution_amount'].sum()
Out[91]:
229.65000000000003

How many times did Wolfe give to Ojeda?

In [92]:
actblue_wolfe_ojeda['contribution_amount'].count()
Out[92]:
99

How did Sibylle Barlow give?

In [93]:
actblue_barlow = read_or_save(
    'actblue_barlow',
    lambda: pd.read_sql("""
    SELECT contribution_date,
           contribution_amount,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE contributor_last_name = 'BARLOW'
      AND contributor_first_name = 'SIBYLLE'
      AND contributor_zip_code ILIKE '01742%'
      --AND coalesce(beneficiary_candidate_office,cand_office) IN ('S',
    --                      'H')
      AND extract(YEAR
                  FROM contribution_date) >= 2017
    GROUP BY contribution_date,
             contribution_amount
    ORDER BY count(*) DESC
    """, con=conn)
)
actblue_barlow['contribution_amount'].describe()
Out[93]:
count   4,877.00
mean        6.26
std        56.45
min         0.10
25%         0.50
50%         2.50
75%         5.00
max     2,700.00
Name: contribution_amount, dtype: float64

How many out of state?

In [94]:
actblue_barlow_out_of_state = read_or_save(
    'actblue_barlow_out_of_state',
    lambda: pd.read_sql("""
    SELECT sum(CASE WHEN contributor_state != coalesce(cand_office_st,beneficiary_candidate_state) THEN 1 ELSE 0 END) as out_of_state,
    sum(CASE WHEN contributor_state = coalesce(cand_office_st,beneficiary_candidate_state) THEN 1 ELSE 0 END) as in_state
    FROM actblue_contribs
    WHERE contributor_last_name = 'BARLOW'
      AND contributor_first_name = 'SIBYLLE'
      AND contributor_zip_code ILIKE '01742%'
      --AND coalesce(beneficiary_candidate_office,cand_office) IN ('S',
    --                      'H')
      AND extract(YEAR
                  FROM contribution_date) >= 2017
    """, con=conn)
)
actblue_barlow_out_of_state
Out[94]:
out_of_state in_state
0 4073 303

How much did William Nottingham give?

In [95]:
actblue_nottingham = read_or_save(
    'actblue_nottingham',
    lambda: pd.read_sql("""
    SELECT *
    FROM actblue_contribs
    WHERE contributor_first_name = 'WILLIAM'
      AND contributor_last_name = 'NOTTINGHAM'
      AND contributor_zip_code ILIKE '90720%'
      AND extract(YEAR
                  FROM contribution_date) >= 2017
    """, con=conn)
)
actblue_nottingham['contribution_amount'].sum()
Out[95]:
7615.0

What's the gender breakdown of ActBlue contribs?

In [96]:
actblue_first_names = read_or_save(
    'actblue_first_names',
    lambda: pd.read_sql("""
    SELECT contributor_first_name,
           count(*),
           sum(contribution_amount)
    FROM actblue_contribs
    WHERE extract(YEAR FROM contribution_date) >= 2017
    and coalesce(beneficiary_candidate_office,cand_office) in ('H','S')
    GROUP BY contributor_first_name
    """, con=conn)
)

d = gender.Detector(case_sensitive=False)

actblue_first_names['gender'] = actblue_first_names['contributor_first_name'].apply(d.get_gender)

What are the most common first names and what gender do we guess those donors are?

In [97]:
actblue_first_names.sort_values(by=['count'], ascending=False).head(5)
Out[97]:
contributor_first_name count sum gender
58433 JOHN 255113 12,025,056.38 male
26279 DAVID 235457 12,658,613.07 male
85072 MICHAEL 212219 10,088,318.41 male
103642 ROBERT 208469 9,789,717.16 male
117025 SUSAN 203822 6,307,945.32 female

What's the overall breakdown by guessed gender?

In [98]:
actblue_gender = actblue_first_names.groupby(actblue_first_names['gender'])['count','sum'].sum()

actblue_gender['percent_by_count'] = actblue_gender['count']/actblue_gender['count'].sum()*100
actblue_gender['percent_by_sum'] = actblue_gender['sum']/actblue_gender['sum'].sum()*100

actblue_gender
Out[98]:
count sum percent_by_count percent_by_sum
gender
andy 98467 3,367,157.39 0.64 0.60
female 7066117 209,183,436.95 46.27 37.11
male 5683018 265,078,157.11 37.21 47.03
mostly_female 739311 22,404,141.40 4.84 3.97
mostly_male 349683 13,945,558.53 2.29 2.47
unknown 1336396 49,706,579.83 8.75 8.82
In [99]:
%%bash
jupyter nbconvert analysis.ipynb
[NbConvertApp] Converting notebook analysis.ipynb to html
[NbConvertApp] Writing 710606 bytes to analysis.html
In [ ]: