<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/deceit-in-politics-an-analysis-of-politifact-data/"></div></div><div><a data-url="https://www.r-bloggers.com/deceit-in-politics-an-analysis-of-politifact-data/" data-counturl="https://www.r-bloggers.com/deceit-in-politics-an-analysis-of-politifact-data/" data-count="horizontal" data-text="Deceit in Politics; An Analysis of PolitiFact Data" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://ntguardian.wordpress.com/2016/11/07/deceit-politics-analysis-politifact-data/"> R – Curtis Miller's Personal Website</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>Naturally, both Hillary Clinton and Donald Trump have been accused of lying; if I had told you in 2012 that both candidates from both political parties were being accused of lies, you would likely have given me a blank, disinterested stare; this alone is not shocking. What <em>is</em> shocking, though, is the level of deceit and how central a theme it was to this campaign season.</p>
<p><span></span></p>
<p>Some accuse the other side of being the liars, the other side counters with a similar accusation, and those not committed to a side like to lazily declare both sides to be equally guilty of lying. It does not take much thought, though, to realize there is no reason why both sides should be equally guilty of lying, and that is especially true for this election.</p>
<p>Donald Trump takes lying to a new level, living in his own invented reality and inviting the rest of America to participate in his nightmarish hallucination that only he can save us from. The media has struggled to handle this. They worry about appearing unfairly biased, and in the past, perhaps behaving as if both sides were equally guilty of lying seemed a good enough proxy to reality to avoid coming across as biased. But Donald Trump lies so much it’s thrown them off their toes (if you don’t believe me, read on; I have evidence later), and his candidacy has sparked a conversation in the media world about how to handle a candidate so casually dishonest he himself may not know what is true and what is not.</p>
<p>Here, I’m going to use R to dig deeper into the question about how honest are our politicians, and whether one party lies more than another. All of my data was scraped from <a target="_blank" rel="nofollow" href="http://www.politifact.com/">PolitiFact’s website</a>, a popular and well-known fact checker with an excellent categorization system that makes analyzing their data easier. I present various graphics and tables showing who lies more, and what they lie about.</p>
<h2>Data Extraction and Analysis</h2>
<p>Before scraping, I use MySQL to create a database that will hold the data I scrape from PolitiFact. The SQL statements that define the tables in the database <code>politifactscraper</code> are shown below.</p>
<pre>
/* PolitiFactScraper_define.sql
 *
 * Defines tables used to hold information for my PolitiFact web scraper.
 */

/* Rating: contains rating schema
    aid: The rating id
    label: The name of the rating
*/
create table Rating (
    aid int auto_increment primary key,
    label char(15)
) auto_increment = 0;

/* Party: contains (political) party schema
    rid: The id of the party
    name: Contains the name of the party
*/
create table Party (
    rid int auto_increment primary key,
    name char(50)
) auto_increment = 0;

/* Speaker: Contains details about speakers for which statements exist
    pid: The id of the speaker
    name: The name of the speaker
    rid: The id of the party with whom the speaker is affiliated
*/
create table Speaker (
    pid int auto_increment primary key,
    name varchar(140) not null,
    rid int,
    foreign key (rid) references Party (rid) on update cascade on delete set null
) auto_increment = 1;

/* Stmnt: Contains statements made
    sid: The id of the statement
    aid: The id of the rating given to the statement
    text: The statement's text
    s_date: The date on which the statement was made
*/
create table Stmnt (
    sid int auto_increment primary key,
    aid int,
    text varchar(2000) not null,
    s_date date,
    pid int not null,
    foreign key (pid) references Speaker (pid) on update cascade on delete cascade,
    foreign key (aid) references Rating (aid) on update cascade on delete set null
) auto_increment = 1;

/* About: Contains relations identifying an individual about whom the statement was made
    sid: The id of the statement
    pid: The id of the person about whom the statement was made

    NOTE: This table is not used currently
*/
create table About (
    sid int not null,
    pid int not null,
    primary key (sid, pid),
    foreign key (sid) references Stmnt (sid) on update cascade on delete cascade,
    foreign key (pid) references Speaker (pid) on update cascade on delete cascade
);
</pre>
<p>I wrote a Python program to scrape the data from PolitiFact and save the data in the database <code>politifactscraper</code>. The code for the program is listed below:</p>
<pre>
from bs4 import BeautifulSoup
from urllib.request import urlopen
from urllib.error import *
from datetime import datetime
import time
import html
import dateparser
import requests
import string
import pymysql as sql

def get_statements(people_dict):
    &quot;&quot;&quot;
    :param people_dict: dict; A dictionary object with names for indices and a string of the form &quot;/personalities/im-a-person/&quot; that will be appended to the end of a PolitiFact URL

    :return: dict; A dict containing two entries: &quot;Statements&quot;, with a list containing tuples of the form (name, url, page number, rating, date, text); and &quot;Errors&quot;, a list of URLs that failed to be scraped

    This function scrapes PolitiFact's website, extracting information for all persons in people_dict and returning a list with tuples with the scraped information.
    &quot;&quot;&quot;

    # Prepare session
    session = requests.Session()
    headers = {&quot;User-Agent&quot;:&quot;Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36&quot;,
               &quot;Accept-Language&quot;:&quot;en-US,en;q=0.8&quot;,
               &quot;Accept&quot;:&quot;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&quot;}
    waittime = 10     # Don't want to go too fast (preferred time according to site's robost.txt)
    politifact_base = &quot;http://www.politifact.com&quot;
    statements = set()
    error_pages = list()

    for name, link in people_dict.items():
        page = 0
        time.sleep(waittime + 1)     # Don't go too fast
        try:
            # Get page and process via BeautifulSoup
            src = session.get(politifact_base + link + &quot;statements/?page=1&quot;, headers = headers)
            statement_pg = BeautifulSoup(src.text, &quot;lxml&quot;)
            # Below's latter condition checks to see if there are more pages to &quot;click&quot;
            while page == 0 or statement_pg.find(&quot;&quot;, {&quot;title&quot;: &quot;Next&quot;}) != None:
                page += 1     # Update page number
                try:
                    if page > 1:
                        # If we're on a new page, read it
                        time.sleep(waittime + 1)
                        src = session.get(politifact_base + link + &quot;statements/?page=&quot; + str(page), headers = headers)
                    statement_pg = BeautifulSoup(src.text, &quot;lxml&quot;)
                    # Begin processing statements
                    for s in statement_pg.findAll(&quot;&quot;, {&quot;class&quot;: &quot;statement&quot;}):
                        if s.find(&quot;div&quot;, {&quot;class&quot;:&quot;statement__source&quot;}).a.get(&quot;href&quot;) == link:
                            # This statement was made by the individual who's page we are on
                            try:
                                statements.add((name.replace('  ', ' '),
                                                politifact_base + link,
                                                page,
                                                s.find(&quot;div&quot;, {&quot;class&quot;:&quot;meter&quot;}).img.get(&quot;alt&quot;),
                                                dateparser.parse(s.find(&quot;span&quot;, {&quot;class&quot;:&quot;article__meta&quot;}).get_text()[3:]),
                                                s.find(&quot;p&quot;, {&quot;class&quot;:&quot;statement__text&quot;}).a.get_text().strip().replace('\xa0', ' ')))
                            except:
                                # If something bad happens, add a blank entry
                                statements.add((name.replace('  ', ' '),
                                                politifact_base + link,
                                                page,
                                                None,
                                                None,
                                                None))
                except URLError as e:
                    # Print errors and add to list of error pages
                    print(e)
                    error_pages.append((name, politifact_base + link + &quot;statements/?page=&quot; + str(page)))
        except URLError as e:
            print(e)
            error_pages.append((name, politifact_base + link + &quot;statements/?page=1&quot;))

    return {&quot;Statements&quot;: list(statements), &quot;Errors&quot;: error_pages}

def speakers_to_db(people_dict, party, cur):
    &quot;&quot;&quot;
    :param people_dict: dict; A dictionary object with names for indices and a string of the form &quot;/personalities/im-a-person/&quot; that will be appended to the end of a PolitiFact URL
    :param party: string; An identifier for the political party associated with the individuals in people_dict
    :param cur: cursor; A pymysql cursor object

    This function enters the people in people_dict into the speaker table in the MySQL data base connected to by cur. Note that party must be an existing entry in the party table in the data base.
    &quot;&quot;&quot;

    # Get party rid identifier
    res = cur.execute(&quot;select rid from party where name=\&quot;&quot; + party + &quot;\&quot;;&quot;)
    if res == 1:
        rid = cur.fetchone()[0]
    else:
        raise RuntimeError(&quot;When I looked up party &quot; + party + &quot; in database I did not get exactly one result!&quot;)

    # Populate database
    for name in people_dict.keys():
        res = cur.execute(&quot;select name, rid from speaker where name='&quot; + name.replace(&quot;'&quot;, &quot;''&quot;) + &quot;' and rid=&quot; + str(rid) + &quot;;&quot;)
        if res == 0:
            cur.execute(&quot;insert into speaker (name, rid) values ('&quot; + name.replace(&quot;'&quot;, &quot;''&quot;) +&quot;',&quot; + str(rid) + &quot;);&quot;)

    cur.connection.commit()

def statements_to_db(stmnt_list, party, cur):
    &quot;&quot;&quot;
    :param stmnt_list: list; A list containing statements to be entered into the data base connected to by cur
    :param party: string; A string identifying the party associated with the statements
    :param cur: cursor; A pymysql cursor object

    This function enters the statements in stmnt_list into the smnt table in the data base connected to by cur. Be sure that all speakers in the list are already included in the speaker table in the data base.
    &quot;&quot;&quot;

    # Create table of statement rating aid values
    res = cur.execute(&quot;select * from rating;&quot;)
    # There should be nine rating values
    if res == 9:
        # Table is a reverse crosswalk; given name of rating, it gives the aid value
        aid_table = dict()
        for _ in range(res):
            row = cur.fetchone()
            aid_table[row[1]] = row[0]
    else:
        raise RuntimeError(&quot;Something is wrong with the rating table in database; does not have appropriate number of entries!&quot;)

    # Create table for speakers, giving their pid numbers, all from selected party
    res = cur.execute(&quot;select pid, name from speaker where rid = (select rid from party where name = \&quot;&quot; + party + &quot;\&quot;);&quot;)
    # The table should have at least one person in it
    if res > 0:
        # Table is a reverse crosswalk; given name of speaker, it gives the pid value
        pid_table = dict()
        for _ in range(res):
            row = cur.fetchone()
            pid_table[row[1].replace(&quot;  &quot;, &quot; &quot;)] = row[0]
    else:
        raise RuntimeError(&quot;You should populate the table of speakers before trying to add statements to database!&quot;)

    # We can now finally start adding statements to the table
    for name, _, __, rating, date, text in stmnt_list[&quot;Statements&quot;]:
        cur.execute(&quot;insert into stmnt (pid, aid, s_date, text) values (&quot; +                    str(pid_table[name.replace(&quot;  &quot;, &quot; &quot;)]) + &quot;, &quot; + str(aid_table[rating]) + &quot;, \'&quot; +                     date.strftime('%Y%m%d') + &quot;\', \'&quot; + text.replace(&quot;'&quot;, &quot;''&quot;) + &quot;\');&quot;)

    cur.connection.commit()

def main():
    conn = sql.connect(host='localhost', user = &quot;root&quot;, passwd=my_pass, db=&quot;mysql&quot;, charset = &quot;utf8&quot;)
    cur = conn.cursor()
    cur.execute(&quot;use politifactscraper;&quot;)

    politifact_base = &quot;http://www.politifact.com&quot;
    html = urlopen(politifact_base + &quot;/personalities/&quot;)
    bsObj = BeautifulSoup(html.read(), &quot;lxml&quot;)

    people = bsObj.findAll(&quot;li&quot;, {&quot;class&quot;: &quot;az-list__item&quot;})

    people_affil = [p for p in people if (p.find(&quot;span&quot;, {&quot;class&quot;:&quot;people-party&quot;}) != None)]

    republicans = [p for p in people_affil if (p.find(&quot;span&quot;, {&quot;class&quot;:&quot;people-party&quot;}).get_text() == &quot;Republican&quot;)]
    democrats = [p for p in people_affil if (p.find(&quot;span&quot;, {&quot;class&quot;:&quot;people-party&quot;}).get_text() == &quot;Democrat&quot;)]
    independents = [p for p in people_affil if (p.find(&quot;span&quot;, {&quot;class&quot;:&quot;people-party&quot;}).get_text() == &quot;Independent&quot;)]
    libertarians = [p for p in people_affil if (p.find(&quot;span&quot;, {&quot;class&quot;:&quot;people-party&quot;}).get_text() == &quot;Libertarian&quot;)]

    r_links = dict([(p.a.get_text(), p.a.get(&quot;href&quot;)) for p in republicans])
    d_links = dict([(p.a.get_text(), p.a.get(&quot;href&quot;)) for p in democrats])
    i_links = dict([(p.a.get_text(), p.a.get(&quot;href&quot;)) for p in independents])
    l_links = dict([(p.a.get_text(), p.a.get(&quot;href&quot;)) for p in libertarians])

    # Manually add notorious individuals
    r_links.update({
            &quot;Mitch McConnel&quot;: &quot;/personalities/mitch-mcconnell/&quot;,
            &quot;Paul Ryan&quot;: &quot;/personalities/paul-ryan/&quot;
        })
    d_links.update({
            &quot;Barack Obama&quot;: &quot;/personalities/barack-obama/&quot;,
            &quot;Joe Biden&quot;: &quot;/personalities/joe-biden/&quot;,
            &quot;Nancy Pelosi&quot;: &quot;/personalities/nancy-pelosi/&quot;,
            &quot;Harry Reid&quot;: &quot;/personalities/harry-reid/&quot;
        })

    # Links for select individuals
    u_links = {
        &quot;Bloggers&quot;: &quot;/personalities/blog-posting/&quot;,
        &quot;Facebook posts&quot;: &quot;/personalities/facebook-posts/&quot;,
        &quot;Chain email&quot;: &quot;/personalities/chain-email/&quot;
    }

    speakers_to_db(l_links,&quot;Libertarian&quot;,cur)
    speakers_to_db(r_links,&quot;Republican&quot;,cur)
    speakers_to_db(d_links,&quot;Democrat&quot;,cur)
    speakers_to_db(i_links,&quot;Independent&quot;,cur)
    speakers_to_db(u_links,&quot;Unaffiliated&quot;,cur)

    l_statements = get_statements(l_links)
    d_statements = get_statements(d_links)
    r_statements = get_statements(r_links)
    i_statements = get_statements(i_links)
    u_statements = get_statements(u_links)

    statements_to_db(l_statements, &quot;Libertarian&quot;, cur)
    statements_to_db(d_statements, &quot;Democrat&quot;, cur)
    statements_to_db(r_statements, &quot;Republican&quot;, cur)
    statements_to_db(i_statements, &quot;Independent&quot;, cur)
    statements_to_db(u_statements, &quot;Unaffiliated&quot;, cur)

    cur.close()
    conn.close()

if __name__ == '__main__':
    main()
</pre>
<p>Now that the data is in a database, it’s easy to access and process it using either R or Python. I will be using both languages for analyzing this data.</p>
<p>In R, I first assess how honest individuals who associate with a party are (I also include the “Unaffiliated” group, which does not include politicians but the unending stream of bloggers and Facebook/e-mail spam that we see on a daily basis). PolitiFact ratings can be seen as ordinal data, which means that metrics based on order, such as the median are well-defined. I base judgement of honesty on the median first, then break ties using the mean (which is not well-defined for this data). In the data base, I conveniently assigned the values in the <code>aid</code> column of the <code>rating</code> table so that it reflects the order of “honesty” for each possible rating, with 0 for “Pants on Fire!” and 5 for “True” (the flip-flopping scores have values 6 for “Full Flop” to 8 for “No Flip”, but are excluded in further analysis). The result is shown below:</p>
<pre>
library(dplyr)
library(magrittr)
library(htmlTable)
library(reshape2)
library(vcd)

# Get access to data base
db &lt;- src_mysql(&quot;politifactscraper&quot;, password = my_pswd)
# Begin working with data base with dplyr
db %>%
    # Get stmnt table
    tbl(&quot;stmnt&quot;) %>%
    # Need to join with speaker table to get party id
    left_join(tbl(db, &quot;speaker&quot;), by = &quot;pid&quot;) %>%
    as.data.frame %>%
    # Exclude flops
    filter(aid &lt;= 5) %>%
    group_by(rid) %>%
    # Compute desired metrics per party
    summarize(med = median(aid), avg = mean(aid), num = length(aid)) %>%
    # Get party names
    left_join(tbl(db, &quot;party&quot;) %>% as.data.frame, by = &quot;rid&quot;) %>%
    arrange(desc(med), desc(avg)) %>%
    select(name, med, avg, num) %>%
    # Get rating names
    left_join(tbl(db, &quot;rating&quot;) %>% as.data.frame, by = c(&quot;med&quot; = &quot;aid&quot;)) %>%
    mutate(avg = round(avg, digits = 2)) %$%
    # Finally put in a pretty HTML table for display in markdown
    htmlTable(select(., &quot;Median Honesty&quot; = label, &quot;Average Honesty Score&quot; = avg, &quot;Rated Statements&quot; = num), rnames = name, caption = &quot;Party Honesty&quot;, tfoot = &quot;Data source: PolitiFact&quot;)
</pre>
<table>
<thead>
<tr>
<td colspan="4">
Party Honesty</td>
</tr>
<tr>
<th> </th>
<th>Median Honesty</th>
<th>Average Honesty Score</th>
<th>Rated Statements</th>
</tr>
</thead>
<tbody>
<tr>
<td>Independent</td>
<td>Mostly True</td>
<td>3.25</td>
<td>181</td>
</tr>
<tr>
<td>Democrat</td>
<td>Half-True</td>
<td>3.07</td>
<td>4026</td>
</tr>
<tr>
<td>Libertarian</td>
<td>Half-True</td>
<td>2.92</td>
<td>147</td>
</tr>
<tr>
<td>Republican</td>
<td>Half-True</td>
<td>2.57</td>
<td>5480</td>
</tr>
<tr>
<td>Unaffiliated</td>
<td>Pants on Fire!</td>
<td>1.06</td>
<td>350</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4">
Data source: PolitiFact</td>
</tr>
</tfoot>
</table>
<p>It seems that Independents, in the aggregate, tell the truth the most, and Republicans the least. While Democrats, Libertarians, and Republicans all have median honesty scores of “Half-True”, the tie-breaker suggests Democrats are the most honest, Republicans the least. Interestingly, PolitiFact rates Republicans more often than Democrats.</p>
<p>As for the Unaffiliated group, take anything you see on Facebook, on some random dude’s blog, or in a chain e-mail with a grain of salt; their median honesty is “Pants on Fire!”</p>
<p>Okay, so that’s the parties. What about individuals? I repeat the above pipeline to see the the top 20 most honest individuals on PolitiFact. Because some people have only a couple ratings in file, I require that PolitiFact have rated at least 15 statements made by the individual to be included in the following lists.</p>
<pre>
db %>%
    # Get stmnt table
    tbl(&quot;stmnt&quot;) %>%
    as.data.frame %>%
    # Exclude flops
    filter(aid &lt;= 5) %>%
    group_by(pid) %>%
    # Compute desired metrics per person (round ratings up, if needed)
    summarize(med = ceiling(median(aid)), avg = mean(aid), num = length(aid)) %>%
    filter(num > 15) %>%
    arrange(desc(med), desc(avg)) %>%
    slice(1:20) %>%
    # Need to join with speaker table to get speaker information
    left_join(tbl(db, &quot;speaker&quot;) %>% as.data.frame, by = &quot;pid&quot;) %>%
    # Get party names
    left_join(tbl(db, &quot;party&quot;) %>% rename(&quot;p_name&quot; = name) %>% as.data.frame, by = &quot;rid&quot;) %>%
    select(name, p_name, med, avg, num) %>%
    # # Get rating names
    left_join(tbl(db, &quot;rating&quot;) %>% as.data.frame, by = c(&quot;med&quot; = &quot;aid&quot;)) %>%
    mutate(avg = round(avg, digits = 2)) %$%
    # # Finally put in a pretty HTML table for display in markdown
    htmlTable(select(., &quot;Party&quot; = p_name, &quot;Median Honesty&quot; = label, &quot;Average Honesty Score&quot; = avg, &quot;Rated Statements&quot; = num), rnames = name, caption = &quot;Tope 20 Honest Entites&quot;, tfoot = &quot;Data source: PolitiFact&quot;)
</pre>
<table>
<thead>
<tr>
<td colspan="5">
Tope 20 Honest Entites</td>
</tr>
<tr>
<th> </th>
<th>Party</th>
<th>Median Honesty</th>
<th>Average Honesty Score</th>
<th>Rated Statements</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alex Sink</td>
<td>Democrat</td>
<td>True</td>
<td>4</td>
<td>19</td>
</tr>
<tr>
<td>Dennis Kucinich</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.84</td>
<td>25</td>
</tr>
<tr>
<td>Sheldon Whitehouse</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.79</td>
<td>24</td>
</tr>
<tr>
<td>Cory Booker</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.6</td>
<td>20</td>
</tr>
<tr>
<td>Mark Warner</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.6</td>
<td>20</td>
</tr>
<tr>
<td>Gina Raimondo</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.59</td>
<td>17</td>
</tr>
<tr>
<td>Sherrod Brown</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.59</td>
<td>34</td>
</tr>
<tr>
<td>Rob Portman</td>
<td>Republican</td>
<td>Mostly True</td>
<td>3.57</td>
<td>47</td>
</tr>
<tr>
<td>Bill Nelson</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.48</td>
<td>25</td>
</tr>
<tr>
<td>David Axelrod</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.39</td>
<td>18</td>
</tr>
<tr>
<td>Hillary Clinton</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.34</td>
<td>292</td>
</tr>
<tr>
<td>Bernie Sanders</td>
<td>Independent</td>
<td>Mostly True</td>
<td>3.25</td>
<td>107</td>
</tr>
<tr>
<td>John Kasich</td>
<td>Republican</td>
<td>Mostly True</td>
<td>3.25</td>
<td>64</td>
</tr>
<tr>
<td>Fred Thompson</td>
<td>Republican</td>
<td>Mostly True</td>
<td>3.25</td>
<td>16</td>
</tr>
<tr>
<td>Bill Richardson</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.24</td>
<td>17</td>
</tr>
<tr>
<td>Alan Grayson</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.18</td>
<td>34</td>
</tr>
<tr>
<td>Bill White</td>
<td>Democrat</td>
<td>Mostly True</td>
<td>3.08</td>
<td>26</td>
</tr>
<tr>
<td>Tim Kaine</td>
<td>Democrat</td>
<td>Half-True</td>
<td>3.38</td>
<td>50</td>
</tr>
<tr>
<td>Nathan Deal</td>
<td>Republican</td>
<td>Half-True</td>
<td>3.37</td>
<td>49</td>
</tr>
<tr>
<td>Bill Clinton</td>
<td>Democrat</td>
<td>Half-True</td>
<td>3.29</td>
<td>41</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
Data source: PolitiFact</td>
</tr>
</tfoot>
</table>
<p><a target="_blank" rel="nofollow" href="https://en.wikipedia.org/wiki/Alex_Sink">Alex Sink</a>, a Florida Democrat who ran for governor and the House of Representatives (and lost both races) has the highest rating. <a target="_blank" rel="nofollow" href="http://www.portman.senate.gov/public/">Rob Portman</a>, the junior Senator from Ohio, is the most honest Republican, and Bernie Sanders the most honest Independent. Of those who ran for President in the 2016 election, Hillary Clinton, according to PolitiFact’s ratings, was the most honest candidate (Bernie Sanders was a close second), and John Kasich was the most honest Republican (in fact, tied with Bernie Sanders). Barack Obama, interestingly, does not appear on this list.</p>
<p>And now the list of shame: The most <em>dishonest</em> individuals.</p>
<pre>
db %>%
    # Get stmnt table
    tbl(&quot;stmnt&quot;) %>%
    as.data.frame %>%
    # Exclude flops
    filter(aid &lt;= 5) %>%
    group_by(pid) %>%
    # Compute desired metrics per person (round ratings up, if needed)
    summarize(med = ceiling(median(aid)), avg = mean(aid), num = length(aid)) %>%
    filter(num > 15) %>%
    arrange(med, avg) %>%
    slice(1:20) %>%
    # Need to join with speaker table to get speaker information
    left_join(tbl(db, &quot;speaker&quot;) %>% as.data.frame, by = &quot;pid&quot;) %>%
    # Get party names
    left_join(tbl(db, &quot;party&quot;) %>% rename(&quot;p_name&quot; = name) %>% as.data.frame, by = &quot;rid&quot;) %>%
    select(name, p_name, med, avg, num) %>%
    # # Get rating names
    left_join(tbl(db, &quot;rating&quot;) %>% as.data.frame, by = c(&quot;med&quot; = &quot;aid&quot;)) %>%
    mutate(avg = round(avg, digits = 2)) %$%
    # # Finally put in a pretty HTML table for display in markdown
    htmlTable(select(., &quot;Party&quot; = p_name, &quot;Median Honesty&quot; = label, &quot;Average Honesty Score&quot; = avg, &quot;Rated Statements&quot; = num), rnames = name, caption = &quot;Tope 20 Dishonest Entities&quot;, tfoot = &quot;Data source: PolitiFact&quot;)
</pre>
<table>
<thead>
<tr>
<td colspan="5">
Tope 20 Dishonest Entities</td>
</tr>
<tr>
<th> </th>
<th>Party</th>
<th>Median Honesty</th>
<th>Average Honesty Score</th>
<th>Rated Statements</th>
</tr>
</thead>
<tbody>
<tr>
<td>Chain email</td>
<td>Unaffiliated</td>
<td>Pants on Fire!</td>
<td>0.78</td>
<td>178</td>
</tr>
<tr>
<td>Bloggers</td>
<td>Unaffiliated</td>
<td>Pants on Fire!</td>
<td>0.92</td>
<td>72</td>
</tr>
<tr>
<td>Democratic Party of Wisconsin</td>
<td>Democrat</td>
<td>False</td>
<td>1.5</td>
<td>24</td>
</tr>
<tr>
<td>Ben Carson</td>
<td>Republican</td>
<td>False</td>
<td>1.54</td>
<td>28</td>
</tr>
<tr>
<td>Michele Bachmann</td>
<td>Republican</td>
<td>False</td>
<td>1.59</td>
<td>61</td>
</tr>
<tr>
<td>Facebook posts</td>
<td>Unaffiliated</td>
<td>False</td>
<td>1.65</td>
<td>100</td>
</tr>
<tr>
<td>Herman Cain</td>
<td>Republican</td>
<td>False</td>
<td>1.77</td>
<td>26</td>
</tr>
<tr>
<td>Donald Trump</td>
<td>Republican</td>
<td>False</td>
<td>1.82</td>
<td>327</td>
</tr>
<tr>
<td>Ken Cuccinelli</td>
<td>Republican</td>
<td>False</td>
<td>2.2</td>
<td>20</td>
</tr>
<tr>
<td>Democratic Congressional Campaign Committee</td>
<td>Democrat</td>
<td>Mostly False</td>
<td>1.44</td>
<td>34</td>
</tr>
<tr>
<td>National Republican Senatorial Committee</td>
<td>Republican</td>
<td>Mostly False</td>
<td>1.87</td>
<td>30</td>
</tr>
<tr>
<td>Allen West</td>
<td>Republican</td>
<td>Mostly False</td>
<td>1.88</td>
<td>26</td>
</tr>
<tr>
<td>Paul Broun</td>
<td>Republican</td>
<td>Mostly False</td>
<td>2</td>
<td>19</td>
</tr>
<tr>
<td>National Republican Congressional Committee</td>
<td>Republican</td>
<td>Mostly False</td>
<td>2.08</td>
<td>53</td>
</tr>
<tr>
<td>Reince Priebus</td>
<td>Republican</td>
<td>Mostly False</td>
<td>2.12</td>
<td>24</td>
</tr>
<tr>
<td>Ted Cruz</td>
<td>Republican</td>
<td>Mostly False</td>
<td>2.2</td>
<td>116</td>
</tr>
<tr>
<td>Tommy Thompson</td>
<td>Republican</td>
<td>Mostly False</td>
<td>2.26</td>
<td>27</td>
</tr>
<tr>
<td>Newt Gingrich</td>
<td>Republican</td>
<td>Mostly False</td>
<td>2.27</td>
<td>77</td>
</tr>
<tr>
<td>Republican Party of Florida</td>
<td>Republican</td>
<td>Mostly False</td>
<td>2.29</td>
<td>34</td>
</tr>
<tr>
<td>Rick Santorum</td>
<td>Republican</td>
<td>Mostly False</td>
<td>2.32</td>
<td>59</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
Data source: PolitiFact</td>
</tr>
</tfoot>
</table>
<p>I allowed chain e-mails, bloggers, and Facebook posts to appear in this list just to make the following point: they’re full of shit. Go to legitimate news sources to get your information. (In my defense as a blogger, I try to be pretty transparent; judge my honesty as you will.) The two “Democrats” that appear on this list are organizations, the Democratic Party of Wisconsin (is this why Scott Walker is a thing?) and the DCCC. Ben Carson is the most dishonest individual on this list and thus the most dishonest person who ran for President in the 2016 election season, according to PolitiFact. (In Dr. Carson’s defense, though, I don’t know if it’s “dishonesty” <em>per se</em> or just ignorance/stupidity.) Donald Trump, according to PolitiFact, is <em>extremely</em> dishonest, yet somehow Hillary is the corrupt liar.</p>
<p>98 people in PolitiFact’s data had at least 15 ratings, so here is the full list, with rankings provided:</p>
<pre>
db %>%
    # Get stmnt table
    tbl(&quot;stmnt&quot;) %>%
    as.data.frame %>%
    # Exclude flops
    filter(aid &lt;= 5) %>%
    group_by(pid) %>%
    # Compute desired metrics per person (round ratings up, if needed)
    summarize(med = ceiling(median(aid)), avg = mean(aid), num = length(aid)) %>%
    filter(num > 15) %>%
    arrange(desc(med), desc(avg)) %>%
    # Need to join with speaker table to get speaker information
    left_join(tbl(db, &quot;speaker&quot;) %>% as.data.frame, by = &quot;pid&quot;) %>%
    # Get party names
    left_join(tbl(db, &quot;party&quot;) %>% rename(&quot;p_name&quot; = name) %>% as.data.frame, by = &quot;rid&quot;) %>%
    select(name, p_name, med, avg, num) %>%
    # # Get rating names
    left_join(tbl(db, &quot;rating&quot;) %>% as.data.frame, by = c(&quot;med&quot; = &quot;aid&quot;)) %>%
    mutate(avg = round(avg, digits = 2), rank = row_number()) %$%
    # # Finally put in a pretty HTML table for display in markdown
    htmlTable(select(., &quot;Party&quot; = p_name, &quot;Rank&quot; = rank, &quot;Median Honesty&quot; = label, &quot;Average Honesty Score&quot; = avg, &quot;Rated Statements&quot; = num), rnames = name, caption = &quot;Honesty of Politically Active Entities&quot;, tfoot = &quot;Data source: PolitiFact&quot;)
</pre>
<table>
<thead>
<tr>
<td colspan="6">
Honesty of Politically Active Entities</td>
</tr>
<tr>
<th> </th>
<th>Party</th>
<th>Rank</th>
<th>Median Honesty</th>
<th>Average Honesty Score</th>
<th>Rated Statements</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alex Sink</td>
<td>Democrat</td>
<td>1</td>
<td>True</td>
<td>4</td>
<td>19</td>
</tr>
<tr>
<td>Dennis Kucinich</td>
<td>Democrat</td>
<td>2</td>
<td>Mostly True</td>
<td>3.84</td>
<td>25</td>
</tr>
<tr>
<td>Sheldon Whitehouse</td>
<td>Democrat</td>
<td>3</td>
<td>Mostly True</td>
<td>3.79</td>
<td>24</td>
</tr>
<tr>
<td>Cory Booker</td>
<td>Democrat</td>
<td>4</td>
<td>Mostly True</td>
<td>3.6</td>
<td>20</td>
</tr>
<tr>
<td>Mark Warner</td>
<td>Democrat</td>
<td>5</td>
<td>Mostly True</td>
<td>3.6</td>
<td>20</td>
</tr>
<tr>
<td>Gina Raimondo</td>
<td>Democrat</td>
<td>6</td>
<td>Mostly True</td>
<td>3.59</td>
<td>17</td>
</tr>
<tr>
<td>Sherrod Brown</td>
<td>Democrat</td>
<td>7</td>
<td>Mostly True</td>
<td>3.59</td>
<td>34</td>
</tr>
<tr>
<td>Rob Portman</td>
<td>Republican</td>
<td>8</td>
<td>Mostly True</td>
<td>3.57</td>
<td>47</td>
</tr>
<tr>
<td>Bill Nelson</td>
<td>Democrat</td>
<td>9</td>
<td>Mostly True</td>
<td>3.48</td>
<td>25</td>
</tr>
<tr>
<td>David Axelrod</td>
<td>Democrat</td>
<td>10</td>
<td>Mostly True</td>
<td>3.39</td>
<td>18</td>
</tr>
<tr>
<td>Hillary Clinton</td>
<td>Democrat</td>
<td>11</td>
<td>Mostly True</td>
<td>3.34</td>
<td>292</td>
</tr>
<tr>
<td>Bernie Sanders</td>
<td>Independent</td>
<td>12</td>
<td>Mostly True</td>
<td>3.25</td>
<td>107</td>
</tr>
<tr>
<td>John Kasich</td>
<td>Republican</td>
<td>13</td>
<td>Mostly True</td>
<td>3.25</td>
<td>64</td>
</tr>
<tr>
<td>Fred Thompson</td>
<td>Republican</td>
<td>14</td>
<td>Mostly True</td>
<td>3.25</td>
<td>16</td>
</tr>
<tr>
<td>Bill Richardson</td>
<td>Democrat</td>
<td>15</td>
<td>Mostly True</td>
<td>3.24</td>
<td>17</td>
</tr>
<tr>
<td>Alan Grayson</td>
<td>Democrat</td>
<td>16</td>
<td>Mostly True</td>
<td>3.18</td>
<td>34</td>
</tr>
<tr>
<td>Bill White</td>
<td>Democrat</td>
<td>17</td>
<td>Mostly True</td>
<td>3.08</td>
<td>26</td>
</tr>
<tr>
<td>Tim Kaine</td>
<td>Democrat</td>
<td>18</td>
<td>Half-True</td>
<td>3.38</td>
<td>50</td>
</tr>
<tr>
<td>Nathan Deal</td>
<td>Republican</td>
<td>19</td>
<td>Half-True</td>
<td>3.37</td>
<td>49</td>
</tr>
<tr>
<td>Bill Clinton</td>
<td>Democrat</td>
<td>20</td>
<td>Half-True</td>
<td>3.29</td>
<td>41</td>
</tr>
<tr>
<td>Barack Obama</td>
<td>Democrat</td>
<td>21</td>
<td>Half-True</td>
<td>3.28</td>
<td>596</td>
</tr>
<tr>
<td>Jeb Bush</td>
<td>Republican</td>
<td>22</td>
<td>Half-True</td>
<td>3.24</td>
<td>79</td>
</tr>
<tr>
<td>John Cornyn</td>
<td>Republican</td>
<td>23</td>
<td>Half-True</td>
<td>3.23</td>
<td>26</td>
</tr>
<tr>
<td>Barbara Buono</td>
<td>Democrat</td>
<td>24</td>
<td>Half-True</td>
<td>3.12</td>
<td>16</td>
</tr>
<tr>
<td>Charlie Crist</td>
<td>Democrat</td>
<td>25</td>
<td>Half-True</td>
<td>3.12</td>
<td>80</td>
</tr>
<tr>
<td>George LeMieux</td>
<td>Republican</td>
<td>26</td>
<td>Half-True</td>
<td>3.12</td>
<td>17</td>
</tr>
<tr>
<td>Wendy Davis</td>
<td>Democrat</td>
<td>27</td>
<td>Half-True</td>
<td>3.07</td>
<td>27</td>
</tr>
<tr>
<td>David Cicilline</td>
<td>Democrat</td>
<td>28</td>
<td>Half-True</td>
<td>3.07</td>
<td>29</td>
</tr>
<tr>
<td>Gary Johnson</td>
<td>Libertarian</td>
<td>29</td>
<td>Half-True</td>
<td>3.06</td>
<td>51</td>
</tr>
<tr>
<td>Kay Bailey Hutchison</td>
<td>Republican</td>
<td>30</td>
<td>Half-True</td>
<td>3.06</td>
<td>17</td>
</tr>
<tr>
<td>Rand Paul</td>
<td>Republican</td>
<td>31</td>
<td>Half-True</td>
<td>3.04</td>
<td>51</td>
</tr>
<tr>
<td>Joe Biden</td>
<td>Democrat</td>
<td>32</td>
<td>Half-True</td>
<td>2.99</td>
<td>75</td>
</tr>
<tr>
<td>George Allen</td>
<td>Republican</td>
<td>33</td>
<td>Half-True</td>
<td>2.96</td>
<td>26</td>
</tr>
<tr>
<td>Paul Ryan</td>
<td>Republican</td>
<td>34</td>
<td>Half-True</td>
<td>2.95</td>
<td>65</td>
</tr>
<tr>
<td>Martin O’Malley</td>
<td>Democrat</td>
<td>35</td>
<td>Half-True</td>
<td>2.94</td>
<td>18</td>
</tr>
<tr>
<td>Tim Pawlenty</td>
<td>Republican</td>
<td>36</td>
<td>Half-True</td>
<td>2.94</td>
<td>17</td>
</tr>
<tr>
<td>Chris Christie</td>
<td>Republican</td>
<td>37</td>
<td>Half-True</td>
<td>2.93</td>
<td>102</td>
</tr>
<tr>
<td>Bob McDonnell</td>
<td>Republican</td>
<td>38</td>
<td>Half-True</td>
<td>2.91</td>
<td>35</td>
</tr>
<tr>
<td>Jon Huntsman</td>
<td>Republican</td>
<td>39</td>
<td>Half-True</td>
<td>2.89</td>
<td>18</td>
</tr>
<tr>
<td>Tammy Baldwin</td>
<td>Democrat</td>
<td>40</td>
<td>Half-True</td>
<td>2.88</td>
<td>25</td>
</tr>
<tr>
<td>John McCain</td>
<td>Republican</td>
<td>41</td>
<td>Half-True</td>
<td>2.88</td>
<td>183</td>
</tr>
<tr>
<td>Greg Abbott</td>
<td>Republican</td>
<td>42</td>
<td>Half-True</td>
<td>2.86</td>
<td>43</td>
</tr>
<tr>
<td>Ron Paul</td>
<td>Republican</td>
<td>43</td>
<td>Half-True</td>
<td>2.85</td>
<td>40</td>
</tr>
<tr>
<td>Marco Rubio</td>
<td>Republican</td>
<td>44</td>
<td>Half-True</td>
<td>2.84</td>
<td>148</td>
</tr>
<tr>
<td>Gwen Moore</td>
<td>Democrat</td>
<td>45</td>
<td>Half-True</td>
<td>2.84</td>
<td>19</td>
</tr>
<tr>
<td>Kendrick Meek</td>
<td>Democrat</td>
<td>46</td>
<td>Half-True</td>
<td>2.84</td>
<td>19</td>
</tr>
<tr>
<td>Lincoln Chafee</td>
<td>Democrat</td>
<td>47</td>
<td>Half-True</td>
<td>2.83</td>
<td>18</td>
</tr>
<tr>
<td>Russ Feingold</td>
<td>Democrat</td>
<td>48</td>
<td>Half-True</td>
<td>2.81</td>
<td>21</td>
</tr>
<tr>
<td>Debbie Wasserman Schultz</td>
<td>Democrat</td>
<td>49</td>
<td>Half-True</td>
<td>2.81</td>
<td>47</td>
</tr>
<tr>
<td>Mitch McConnel</td>
<td>Republican</td>
<td>50</td>
<td>Half-True</td>
<td>2.79</td>
<td>28</td>
</tr>
<tr>
<td>Rick Scott</td>
<td>Republican</td>
<td>51</td>
<td>Half-True</td>
<td>2.77</td>
<td>142</td>
</tr>
<tr>
<td>Karl Rove</td>
<td>Republican</td>
<td>52</td>
<td>Half-True</td>
<td>2.76</td>
<td>17</td>
</tr>
<tr>
<td>Ron Johnson</td>
<td>Republican</td>
<td>53</td>
<td>Half-True</td>
<td>2.73</td>
<td>44</td>
</tr>
<tr>
<td>Mitt Romney</td>
<td>Republican</td>
<td>54</td>
<td>Half-True</td>
<td>2.7</td>
<td>206</td>
</tr>
<tr>
<td>David Perdue</td>
<td>Republican</td>
<td>55</td>
<td>Half-True</td>
<td>2.69</td>
<td>16</td>
</tr>
<tr>
<td>Republican National Committee</td>
<td>Republican</td>
<td>56</td>
<td>Half-True</td>
<td>2.68</td>
<td>34</td>
</tr>
<tr>
<td>Scott Walker</td>
<td>Republican</td>
<td>57</td>
<td>Half-True</td>
<td>2.67</td>
<td>172</td>
</tr>
<tr>
<td>Mary Burke</td>
<td>Democrat</td>
<td>58</td>
<td>Half-True</td>
<td>2.65</td>
<td>34</td>
</tr>
<tr>
<td>Florida Democratic Party</td>
<td>Democrat</td>
<td>59</td>
<td>Half-True</td>
<td>2.64</td>
<td>25</td>
</tr>
<tr>
<td>Rudy Giuliani</td>
<td>Republican</td>
<td>60</td>
<td>Half-True</td>
<td>2.6</td>
<td>47</td>
</tr>
<tr>
<td>Rick Perry</td>
<td>Republican</td>
<td>61</td>
<td>Half-True</td>
<td>2.59</td>
<td>169</td>
</tr>
<tr>
<td>Mike Pence</td>
<td>Republican</td>
<td>62</td>
<td>Half-True</td>
<td>2.58</td>
<td>38</td>
</tr>
<tr>
<td>Tom Barrett</td>
<td>Democrat</td>
<td>63</td>
<td>Half-True</td>
<td>2.52</td>
<td>25</td>
</tr>
<tr>
<td>Republican Governors Association</td>
<td>Republican</td>
<td>64</td>
<td>Half-True</td>
<td>2.5</td>
<td>18</td>
</tr>
<tr>
<td>Harry Reid</td>
<td>Democrat</td>
<td>65</td>
<td>Half-True</td>
<td>2.5</td>
<td>24</td>
</tr>
<tr>
<td>Ted Strickland</td>
<td>Democrat</td>
<td>66</td>
<td>Half-True</td>
<td>2.48</td>
<td>21</td>
</tr>
<tr>
<td>Nancy Pelosi</td>
<td>Democrat</td>
<td>67</td>
<td>Half-True</td>
<td>2.38</td>
<td>29</td>
</tr>
<tr>
<td>John Boehner</td>
<td>Republican</td>
<td>68</td>
<td>Mostly False</td>
<td>2.64</td>
<td>69</td>
</tr>
<tr>
<td>Mike Huckabee</td>
<td>Republican</td>
<td>69</td>
<td>Mostly False</td>
<td>2.63</td>
<td>41</td>
</tr>
<tr>
<td>Eric Cantor</td>
<td>Republican</td>
<td>70</td>
<td>Mostly False</td>
<td>2.56</td>
<td>34</td>
</tr>
<tr>
<td>Dick Cheney</td>
<td>Republican</td>
<td>71</td>
<td>Mostly False</td>
<td>2.53</td>
<td>17</td>
</tr>
<tr>
<td>Carly Fiorina</td>
<td>Republican</td>
<td>72</td>
<td>Mostly False</td>
<td>2.45</td>
<td>22</td>
</tr>
<tr>
<td>Dan Patrick</td>
<td>Republican</td>
<td>73</td>
<td>Mostly False</td>
<td>2.41</td>
<td>22</td>
</tr>
<tr>
<td>Terry McAuliffe</td>
<td>Democrat</td>
<td>74</td>
<td>Mostly False</td>
<td>2.4</td>
<td>30</td>
</tr>
<tr>
<td>Josh Mandel</td>
<td>Republican</td>
<td>75</td>
<td>Mostly False</td>
<td>2.39</td>
<td>28</td>
</tr>
<tr>
<td>Crossroads GPS</td>
<td>Republican</td>
<td>76</td>
<td>Mostly False</td>
<td>2.37</td>
<td>19</td>
</tr>
<tr>
<td>David Dewhurst</td>
<td>Republican</td>
<td>77</td>
<td>Mostly False</td>
<td>2.35</td>
<td>40</td>
</tr>
<tr>
<td>Sarah Palin</td>
<td>Republican</td>
<td>78</td>
<td>Mostly False</td>
<td>2.33</td>
<td>39</td>
</tr>
<tr>
<td>Rick Santorum</td>
<td>Republican</td>
<td>79</td>
<td>Mostly False</td>
<td>2.32</td>
<td>59</td>
</tr>
<tr>
<td>Republican Party of Florida</td>
<td>Republican</td>
<td>80</td>
<td>Mostly False</td>
<td>2.29</td>
<td>34</td>
</tr>
<tr>
<td>Newt Gingrich</td>
<td>Republican</td>
<td>81</td>
<td>Mostly False</td>
<td>2.27</td>
<td>77</td>
</tr>
<tr>
<td>Tommy Thompson</td>
<td>Republican</td>
<td>82</td>
<td>Mostly False</td>
<td>2.26</td>
<td>27</td>
</tr>
<tr>
<td>Ted Cruz</td>
<td>Republican</td>
<td>83</td>
<td>Mostly False</td>
<td>2.2</td>
<td>116</td>
</tr>
<tr>
<td>Reince Priebus</td>
<td>Republican</td>
<td>84</td>
<td>Mostly False</td>
<td>2.12</td>
<td>24</td>
</tr>
<tr>
<td>National Republican Congressional Committee</td>
<td>Republican</td>
<td>85</td>
<td>Mostly False</td>
<td>2.08</td>
<td>53</td>
</tr>
<tr>
<td>Paul Broun</td>
<td>Republican</td>
<td>86</td>
<td>Mostly False</td>
<td>2</td>
<td>19</td>
</tr>
<tr>
<td>Allen West</td>
<td>Republican</td>
<td>87</td>
<td>Mostly False</td>
<td>1.88</td>
<td>26</td>
</tr>
<tr>
<td>National Republican Senatorial Committee</td>
<td>Republican</td>
<td>88</td>
<td>Mostly False</td>
<td>1.87</td>
<td>30</td>
</tr>
<tr>
<td>Democratic Congressional Campaign Committee</td>
<td>Democrat</td>
<td>89</td>
<td>Mostly False</td>
<td>1.44</td>
<td>34</td>
</tr>
<tr>
<td>Ken Cuccinelli</td>
<td>Republican</td>
<td>90</td>
<td>False</td>
<td>2.2</td>
<td>20</td>
</tr>
<tr>
<td>Donald Trump</td>
<td>Republican</td>
<td>91</td>
<td>False</td>
<td>1.82</td>
<td>327</td>
</tr>
<tr>
<td>Herman Cain</td>
<td>Republican</td>
<td>92</td>
<td>False</td>
<td>1.77</td>
<td>26</td>
</tr>
<tr>
<td>Facebook posts</td>
<td>Unaffiliated</td>
<td>93</td>
<td>False</td>
<td>1.65</td>
<td>100</td>
</tr>
<tr>
<td>Michele Bachmann</td>
<td>Republican</td>
<td>94</td>
<td>False</td>
<td>1.59</td>
<td>61</td>
</tr>
<tr>
<td>Ben Carson</td>
<td>Republican</td>
<td>95</td>
<td>False</td>
<td>1.54</td>
<td>28</td>
</tr>
<tr>
<td>Democratic Party of Wisconsin</td>
<td>Democrat</td>
<td>96</td>
<td>False</td>
<td>1.5</td>
<td>24</td>
</tr>
<tr>
<td>Bloggers</td>
<td>Unaffiliated</td>
<td>97</td>
<td>Pants on Fire!</td>
<td>0.92</td>
<td>72</td>
</tr>
<tr>
<td>Chain email</td>
<td>Unaffiliated</td>
<td>98</td>
<td>Pants on Fire!</td>
<td>0.78</td>
<td>178</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="6">
Data source: PolitiFact</td>
</tr>
</tfoot>
</table>
<p>Barack Obama appears 21<sup>st</sup> on this list followed by Vice President Joe Biden (32), Speaker of the House Paul Ryan (34), Senate Majority Leader Mitch McConnel (50), Senate Minority Leader Harry Reid (65), and House Minority Leader Nancy Pelosi (67). Finally, it seems the most dishonest Democratic individual is <a target="_blank" rel="nofollow" href="http://www.terrymcauliffe.com/">Terry McAuliffe</a>, the Governor of Virginia.</p>
<p>We can also see what parties account for more honesty/deceit. Below I create a table with the proportion of each rating given each party is responsible for.</p>
<pre>
# A base data frame used throughout
base_df = db %>%
    # Get stmnt table
    tbl(&quot;stmnt&quot;) %>%
    # Need to join with speaker table to get party id
    left_join(tbl(db, &quot;speaker&quot;), by = &quot;pid&quot;) %>%
    as.data.frame %>%
    # Exclude flops
    filter(aid %
    group_by(aid, rid) %>%
    summarize(value = n()) %>%
    left_join(tbl(db, &quot;party&quot;) %>% as.data.frame, by = &quot;rid&quot;) %>%
    left_join(tbl(db, &quot;rating&quot;) %>% as.data.frame, by = &quot;aid&quot;) %>%
    select(name, label, value) %>%
    dcast(label ~ name)
</pre>
<pre>
## Adding missing grouping variables: `aid`
</pre>
<pre>
# Convert to matrix, and get proportions
r_mat = matrix(r_count[,-1] %>% as.matrix, nrow = 6, dimnames = list(r_count$label, names(r_count)[-1]))
# Order rows correctly
r_mat = r_mat[c(&quot;Pants on Fire!&quot;, &quot;False&quot;, &quot;Mostly False&quot;, &quot;Half-True&quot;, &quot;Mostly True&quot;, &quot;True&quot;),]
(r_mat / rowSums(r_mat)) %>%
    round(digits = 2) %>%
    `*`(100) %>%
    htmlTable(caption = &quot;Proportion of Statements of Certain Truthfulness Made by Members of Parties&quot;, tfoot = &quot;Data source: PolitiFact&quot;)
</pre>
<pre>
##                Democrat Independent Libertarian Republican Unaffiliated
## Pants on Fire!       22           0           1         54           22
## False                30           1           1         63            4
## Mostly False         34           2           1         61            2
## Half-True            43           1           2         52            1
## Mostly True          49           3           2         45            1
## True                 48           2           2         48            1
</pre>
<p>Republicans account for a large share of false statements, much more than Democrats. In fact, a chi-square tests rejects the null hypothesis that statement rating and political party are independent.</p>
<pre>
# Chi-Square Test for Independence
chisq.test(r_mat)
</pre>
<pre>
## 
##  Pearson's Chi-squared test
## 
## data:  r_mat
## X-squared = 1260.8, df = 20, p-value % as.data.frame, by = &quot;rid&quot;) %>%
    left_join(tbl(db, &quot;rating&quot;) %>% as.data.frame, by = &quot;aid&quot;) %>%
    select(Rating = label, Party = name.y)

mos_df$Rating %% factor(levels = c(&quot;Pants on Fire!&quot;, &quot;Mostly False&quot;, &quot;False&quot;, &quot;Half-True&quot;, &quot;Mostly True&quot;, &quot;True&quot;))d
mosaic(~ Party + Rating, data = mos_df, shade = TRUE, gp = shading_hsv,  labeling_args = list(abbreviate_labs = c(Rating = TRUE, Party = TRUE)))
</pre>
<p>I would also like to see <em>what</em> people are lying about (as opposed to how much they lie). For this, I'm simply going to make a word cloud, using the Python package <strong>wordcloud</strong> (read more about it <a target="_blank" rel="nofollow" href="http://amueller.github.io/word_cloud/">here</a>). The code for creating the word clouds is listed below:</p>
<pre>
from os import path
from scipy.misc import imread
import matplotlib.pyplot as plt
from pylab import rcParams
import pymysql as sql
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator

# This line is necessary for the plot to appear in a Jupyter notebook
get_ipython().magic('matplotlib inline')
# Control the default size of figures in this Jupyter notebook
rcParams['figure.figsize'] = 30, 18

d = path.dirname(my_pics)

def get_party_statements(name, cur):
    &quot;&quot;&quot;
    :param name: string; The name of the party for which to look up data
    :param cur: cursor; A pymysql cursor object

    :return: dict; Contains strings with two parameters, &quot;truth&quot; and &quot;lie&quot;, that consists of concatenated statements of all members in the political party identified by name

    This object extracts from a database (connected to via cur) statements made by members of a party identified by name. True statements are those with at least a rating of &quot;half-true&quot;; all else are treated as false.
    &quot;&quot;&quot;

    party_true = &quot;&quot;
    party_lie = &quot;&quot;

    # Get all true statements by party
    nstate = cur.execute(&quot;select text from stmnt where aid >= 3 and aid = 0 and aid = 3 and aid = 0 and aid &lt;= 2 and pid = (select pid from speaker where name = \&quot;&quot; + name + &quot;\&quot;)&quot;)
    for i in range(nstate):
        person_lie += &quot; &quot; + cur.fetchone()[0]

    return {&quot;truth&quot;: person_true, &quot;lie&quot;: person_lie}

def generate_wordcloud(text, logo, font):
    &quot;&quot;&quot;
    :param text: string; A text string that will be turned into a word cloud
    :param logo: array; An object representing the image used for masking (implicitly created by imread in scipy)
    :param font: string; An identifier for the font to be used when creating the word cloud

    Creates a word cloud from text using the font specified by parameter font and the mask specified by logo.
    &quot;&quot;&quot;

    wc = WordCloud(font_path = font, background_color=&quot;white&quot;, max_words=200, mask=logo,
               stopwords=STOPWORDS.update([&quot;said&quot;, &quot;say&quot;, &quot;says&quot;]))
    # generate word cloud
    wc.generate(text)

    # create coloring from image
    image_colors = ImageColorGenerator(logo)

    # show
    # recolor wordcloud and show
    # we could also give color_func=image_colors directly in the constructor
    plt.imshow(wc.recolor(color_func=image_colors))
    plt.axis(&quot;off&quot;)
    plt.show()

def main():
    hillary_logo = imread(path.join(d, &quot;Hillary_for_America_2016_logo.png&quot;))
    democrat_logo = imread(path.join(d, &quot;Democratslogo.png&quot;))
    republican_logo = imread(path.join(d, &quot;Republicanlogo.png&quot;))
    trump_face = imread(path.join(d, &quot;DonaldTrump_bp.png&quot;))

    conn = sql.connect(host='localhost', user = &quot;root&quot;, passwd=my_pass, db=&quot;mysql&quot;, charset = &quot;utf8&quot;)
    cur = conn.cursor()
    cur.execute(&quot;use politifactscraper;&quot;)

    r_statements = get_party_statements(&quot;Republican&quot;, cur)
    d_statements = get_party_statements(&quot;Democrat&quot;, cur)

    u_statements = get_party_statements(&quot;Unaffiliated&quot;, cur)

    hillary_statements = get_people_statements(&quot;Hillary Clinton&quot;, cur)
    trump_statements = get_people_statements(&quot;Donald Trump&quot;, cur)

    neutral_font = &quot;OldNewspaperTypes&quot;
    true_font = &quot;BodoniXT&quot;
    lie_font = &quot;DK Coal Brush&quot;

    # Pictures!
    generate_wordcloud(d_statements[&quot;truth&quot;] + &quot; &quot; + d_statements[&quot;lie&quot;], democrat_logo, neutral_font)
    generate_wordcloud(d_statements[&quot;truth&quot;], democrat_logo, true_font)
    generate_wordcloud(d_statements[&quot;lie&quot;], democrat_logo, lie_font)
    generate_wordcloud(r_statements[&quot;truth&quot;] + &quot; &quot; + r_statements[&quot;lie&quot;], republican_logo, neutral_font)
    generate_wordcloud(r_statements[&quot;truth&quot;], republican_logo, true_font)
    generate_wordcloud(r_statements[&quot;lie&quot;], republican_logo, lie_font)
    generate_wordcloud(hillary_statements[&quot;truth&quot;] + &quot; &quot; + hillary_statements[&quot;lie&quot;], hillary_logo, neutral_font)
    generate_wordcloud(hillary_statements[&quot;truth&quot;], hillary_logo, true_font)
    generate_wordcloud(hillary_statements[&quot;lie&quot;], hillary_logo, lie_font)
    generate_wordcloud(trump_statements[&quot;truth&quot;] + &quot; &quot; + trump_statements[&quot;lie&quot;], trump_face, neutral_font)
    generate_wordcloud(trump_statements[&quot;truth&quot;], trump_face, true_font)
    generate_wordcloud(trump_statements[&quot;lie&quot;], trump_face, lie_font)
    generate_wordcloud(u_statements[&quot;truth&quot;] + &quot; &quot; + u_statements[&quot;lie&quot;], internet_logo, neutral_font)
    generate_wordcloud(u_statements[&quot;truth&quot;] , internet_logo, true_font)
    generate_wordcloud(u_statements[&quot;lie&quot;], internet_logo, lie_font)

    cur.close()
    conn.close()

if __name__ == '__main__':
    main()
</pre>
<p>In the process of making these word clouds, I used the fonts <a target="_blank" rel="nofollow" href="http://www.dafont.com/oldnewspapertypes.font">Old Newspaper Types</a>, <a target="_blank" rel="nofollow" href="http://www.dafont.com/bodoni-xt.font">Bodoni XT</a>, and <a target="_blank" rel="nofollow" href="http://www.dafont.com/dk-coal-brush.font">DK Coal Brush</a>. The source for the Donald Trump mask is <a target="_blank" rel="nofollow" href="http://www.coueswhitetail.com/forums/topic/64750-who-do-you-side-with/">here</a> (after some editing), the WordPress, GMail, and Facebook logos were found via Google search, and the rest are from WikiMedia.</p>
<h3>Mosaic Plot</h3>
<p>I first show the mosaic plot I created earlier. As you can see, Republicans account for more falsehood than Democrats, more than if you had expected there to be no relationship between political party and truthfulness. (Blue indicates more than expected, red less than expected.)</p>
<p><img src="https://i1.wp.com/ntguardian.files.wordpress.com/2016/11/rplot.png?w=456&ssl=1" data-recalc-dims="1"></p>
<h3>All Statements Word Clouds</h3>
<p>First, I show a word cloud for all statements made by the entities considered that were rated by PolitiFact, true or not.</p>
<p><img src="https://i2.wp.com/ntguardian.files.wordpress.com/2016/11/democratstatementcloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i0.wp.com/ntguardian.files.wordpress.com/2016/11/republicanstatementcloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i2.wp.com/ntguardian.files.wordpress.com/2016/11/clintonstatementcloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i0.wp.com/ntguardian.files.wordpress.com/2016/11/trumpstatementcloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i2.wp.com/ntguardian.files.wordpress.com/2016/11/internetstatementcloud.png?w=456&ssl=1" data-recalc-dims="1"></p>
<h3>True Statements Word Clouds</h3>
<p>Next I show the word clouds formed by the statements made by the entities considered that PolitiFact has rated as being at least “half-true”.</p>
<p><img src="https://i1.wp.com/ntguardian.files.wordpress.com/2016/11/democrattruecloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i1.wp.com/ntguardian.files.wordpress.com/2016/11/republicantruecloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i1.wp.com/ntguardian.files.wordpress.com/2016/11/clintontruecloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i2.wp.com/ntguardian.files.wordpress.com/2016/11/trumptruecloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i1.wp.com/ntguardian.files.wordpress.com/2016/11/internettruecloud.png?w=456&ssl=1" data-recalc-dims="1"></p>
<h2>False Statements Word Clouds</h2>
<p>Finally, I show the word clouds formed by the statements made by the entities considered that PolitiFact has rated as being at least as dishonest as “mostly false”.</p>
<p><img src="https://i0.wp.com/ntguardian.files.wordpress.com/2016/11/democratliecloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i2.wp.com/ntguardian.files.wordpress.com/2016/11/republicanliecloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i0.wp.com/ntguardian.files.wordpress.com/2016/11/clintonliecloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i0.wp.com/ntguardian.files.wordpress.com/2016/11/trumpliecloud.png?w=456&ssl=1" data-recalc-dims="1"><br>
<img src="https://i0.wp.com/ntguardian.files.wordpress.com/2016/11/internetliecloud.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>What do we see? Naturally, all of this is in the eye of the beholder (word clouds are not “scientific”), but I noticed some patterns. Naturally, the presidential candidates mention their opponents frequently, and they both say many things true or false that involve their opponents. Meanwhile, the political party word clouds are more focused on policy. The words “Scott”, “Walker”, and “Wisconson” appear a lot in the Democrats’ “lie” cloud (perhaps thanks to the Wisconsin Democratic Party, the most dishonest entity in my earlier lists), and Republicans lie <em>a lot</em> about one person: Obama. As for Facebook posts, chain e-mails, and bloggers, they like to talk about Obama, and my guess is that lies propagated through these channels generally suggest something new will be done by Obama this year that will hurt people.</p>
<h2>Thoughts on PolitiFact</h2>
<p>All of the data used in this source comes from one source: PolitiFact. There are those who believe that this makes these results questionable. I would not be a good statistician if I did not disclose potential problems, so here I discuss potential problems my analysis faces.</p>
<h3>Political Bias</h3>
<p>Upon seeing a result saying that PolitiFact rates Republicans as more dishonest than Democrats, conservatives may immediately reach for the “biased” argument, that the people responsible for maintaining PolitiFact (the Tampa Bay Times) have a political agenda that reflects in their scores, and thuse we should not trust their data.</p>
<p>Sure, “bias” (in this typical sense of the word) is a possibility. I will acknowledge the possibility. Unfortunately, though, many have taken to accusing supposedly authoritative sources of being “biased” whenever those sources contradict their existing beliefs. Trump, and especially Trump supporters, have turned this into an art, but Fox News has been laying the foundation for this line of attack for decades and many on the left now resort to it as well (I felt the need to have this discussion after a Bernie Sanders supporter, in a Facebook argument, accused PolitiFact of being biased against Bernie Sanders in favor of Hillary Clinton). It’s a wonderful line of attack, because there’s usually no way for the victim to prove she is not “biased”, or the accuser cares little for whatever proof she finds.</p>
<p>Accusing PolitiFact of being “biased” (along with many other traditional, well-reputed media outlets) quickly angers me. It fuels tribalism by eroding our “common ground” information sources that we accept as reporting an objective, baseline “truth” from which we can then debate the approach to take to society’s problems. Continuing along this path allows one to eventually paint reality as he hallucinates it to be, and anyone who disagrees with that vision with an argument as simple as “that’s not true” is “biased”. If we continue to refuse to accept opposing views because the source is “biased”, we will no longer have a functioning democracy; minds will never change, we will become locked into our tribes of yes-men with common broken-clock media, and voting will simply become a battle of wills between two equally mad fictions.</p>
<p>So if you’re going to criticize these results because PolitiFact is “biased”, you’re further hurtling us to <a target="_blank" rel="nofollow" href="http://www.nytimes.com/2016/08/24/opinion/campaign-stops/the-age-of-post-truth-politics.html">post-truth politics</a>. I will resist this dangerous trend.</p>
<h3>Curation Bias</h3>
<p>While I will simply refuse to entertain the possibility of political bias, there are other ways this data could become “biased” that have little to do with any political beliefs by the individuals at PolitiFact. Fact checking is not a science, and other sources of bias could be introduced.</p>
<p>When I mention “curation bias”, I reference the fact that fact-checkers must decide what to fact-check. They may be drawn to fact-check statements that:</p>
<ul>
<li>Are hot button issues (as a former intern in a lobbying firm, I can promise you that a lot more goes on in Washington than just the headline makers, much of which is important but not nearly as exciting or “sexy” to discuss)</li>
<li>Are made by prominent individuals (Barack Obama has a lot of his statements rated, unlike <a target="_blank" rel="nofollow" href="http://robbishop.house.gov/aboutme/">Rep. Rob Bishop</a>, who’s been in Congress for fourteen years and has not a single statement on record; I was also sad to see Jill Stein did not have a file)</li>
<li>Sound like they may be false (so there is a propensity to show a statement is false than show a statement is true; additionally, the writer may have some initial idea about the truth in the statement, so if a statement with many technical details about an esoteric topic is made, the fact-checker may not consider it)</li>
</ul>
<p>These are more serious threats to the quality of this analysis, ones for which there is no fix and for which the effect is unclear. I won’t dare to claim that my analysis is immune to them and can’t be tainted by bias. Nevertheless, I believe that if we want an idea of honesty in politics, we can’t do much better than use this data.</p>
<h2>Conclusion</h2>
<p>On Tuesday, this nightmare of an election will be over. Americans will cast their votes, and hopefully they make the right decision. I will not lie: I am very nervous about this election. As of this writing, <a target="_blank" rel="nofollow" href="http://projects.fivethirtyeight.com/2016-election-forecast/?ex_cid=rrpromo">FiveThirtyEight</a> is showing a close election. I hope that this analysis will highlight the source of dishonesty in this election, and people will not judge both sides as equally bad or equally guilty. That is simply not the state of reality, and if we are going to move past the problems we have seen in our democracy, we will need to come to terms with reality.</p>
<p> <a target="_blank" rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ntguardian.wordpress.com/1906/"><img alt="" src="http://feeds.wordpress.com/1.0/comments/ntguardian.wordpress.com/1906/" border="0"></a> <img alt="" src="https://i1.wp.com/pixel.wp.com/b.gif?resize=1%2C1&ssl=1" border="0" data-recalc-dims="1"></p>
<p><div><div><div><div data-width="55" data-show-faces="false" data-send="true" data-layout="box_count" data-height="62" data-href="https://www.r-bloggers.com/deceit-in-politics-an-analysis-of-politifact-data/"></div></div><div><a data-url="https://www.r-bloggers.com/deceit-in-politics-an-analysis-of-politifact-data/" data-counturl="https://www.r-bloggers.com/deceit-in-politics-an-analysis-of-politifact-data/" data-count="vertical" data-text="Deceit in Politics; An Analysis of PolitiFact Data" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://ntguardian.wordpress.com/2016/11/07/deceit-politics-analysis-politifact-data/"> R – Curtis Miller's Personal Website</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/?s=data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/?s=Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/?s=map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/?s=animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/?s=RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/?s=sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/?s=LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/?s=SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/?s=eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/?s=git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/?s=hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/?s=Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/?s=regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/?s=PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/?s=time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/?s=trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/sx9nqoQyofs"></a></div>