我最近在Kaggle上看到了美国大选的数据集。既然我们正在热烈讨论2020年的大选,我想分析一下之前的美国总统大选是个好主意。
数据集包含了从1976年到2020年的选举。我会从不同的角度来处理这些数据,试图了解人们是如何投票的。
我将使用pandas库进行数据分析和可视化,因此这也是使用pandas的函数和方法的良好实践。
让我们从导入库并将数据集读入一个Pandas dataframe开始。
importnumpyasnpimportpandasaspdpresident=pd.read_csv("/content/president-1976-2016.csv")
在分析中有一些多余的列。例如state_fips、state_cen和state_ic代表什么可能不是很确定,但它们可以作为一个指示器或状态的唯一值。
我们可以通过检查和比较这些列中的值来确认。这三列有51个惟一值(每个州一个)。
president.state_fips.nunique() 51
对于特定的州,这些列中的值是相同的:
president[president.state=='Alabama'][['state_fips','state_cen','state_ic']].value_counts()state_fipsstate_censtate_ic1634163dtype: int64
由于数据集已经包含状态信息,所以这些列在分析方面是多余的,因此可以删除它们。
office列仅表示这是总统选举,因此它包含一个惟一的值(US President)。version和notes列也没有任何用处。
我们可以使用Pandas的drop函数来删除这些列。
president.drop(['state_po', 'state_fips', 'state_cen', 'state_ic', 'office', 'version', 'notes'], axis=1, inplace=True)
我们准备开始分析,我将分析分为三个部分:
- 一段时间内的总票数
- 每个获胜者的投票比例
- 国家层面的比较
一段时间内的总票数
我们首先要检查的是每次选举的票数。“totalvotes”列显示特定状态下的投票总数。因此,下面的代码将创建一个dataframe,其中包含每个州对于每次选举的总票数。
yearly_votes=president[['year','state','totalvotes']]\.groupby(['year','state']).mean().reset_index() yearly_votes.head()
我们可以对“year”列应用groupby函数,并对“totalvotes”列中的值求和,从而得到每次选举的总票数。
yearly_votes.groupby('year').sum()\.plot(figsize=(10,6), legend=False,title='Total Number of Votes in US Presendial Elections')
我使用了pandas内置的绘图函数来绘制结果。它比使用Matplotlib的pyplot接口更简单,但是对plot的控制较少。
除了1996年和2012年,参加投票的人数一直在稳步增加。这很可能是由于人口增长,因此更好的衡量方法是每百万人口(有资格投票)的票数。粗略比较一下,从1970年(2.03亿)到2010年(3.08亿),人口增长了大约50%。因此,投票人数的比例多年来基本保持不变。
每个获胜者的投票比例
有些选举的结果非常接近,获胜者只以很小的百分比获胜。也有一些选举中获胜者以很大的优势获胜。
我们可以计算出每个获胜者的投票比例。我们将首先在dataframe中添加一个“winner”列。
维基百科页面包含了美国总统的名单。使用read_html函数可以很容易地将这些表读入到一个panda数据框架中。它将web页面中的表转换为数据列表。
dfs=pd.read_html("https://en.wikipedia.org/wiki/List_of_presidents_of_the_United_States") winners=dfs[1][['Election','President.1']] winners.head()
第二个数据列表包含了美国总统的名单。我们只需要1976年到2016年的选举数据。
winners=winners.iloc[-12:-1, :] winners.Election=winners.Election.astype('int64') winners.rename(columns={'President.1':'winner'}, inplace=True) winners
我们需要将名称与总统dataframe中的名称进行格式的统一。pandas的字符串操作能够很好的来完成这个任务:
first_name=winners.winner.str.rsplit(' ', n=1, expand=True)[0] last_name=winners.winner.str.rsplit(' ', n=1, expand=True)[1] winners.winner=last_name+', '+first_namewinners
我们还需要做一些小调整,以便总统的名字完全匹配。
winners.winner[73] ='Bush, George H.W.'winners.winner[78] ='Obama, Barack H.'winners.winner[79] ='Obama, Barack H.'winners.winner[80] ='Trump, Donald J.'
我还将选举日期转换为整数,以便在下一个步骤中使用合并函数。
我们现在可以根据选举年合并“president”和“winners”数据。
president=pd.merge(president, winners, left_on='year', right_on='Election')
我们将过滤president dataframe,只包括对获胜者的投票。
winner_votes=president[president.candidate==president.winner] winner_votes.head()
每行包含获胜者的票数和特定选举在特定州的总票数。一个简单的groupby函数将为我们提供各个国家的值。
total_votes=winner_votes[['year','winner','candidatevotes','totalvotes']]\.groupby(['year','winner']).sum() total_votes
我们可以通过一个简单的数学运算来计算获胜者的比例,并对结果进行排序。
(total_votes.candidatevotes/total_votes.totalvotes)\.sort_values(ascending=False)
第一名是里根的第二任期。
国家层面比较
如果你喜欢政治,你就会知道每个州更可能支持哪个政党。我们用数字来验证一下。
这是winner_votes数据列表。我们将添加一个比率列,即候选人票数除以总票数。
winner_votes['ratio'] =winner_votes.candidatevotes/winner_votes.totalvotes
我们希望看到民主党和共和党都排在前十位的州。下面的groupby操作将返回基于民主党最高平均比率的前10个州。
winner_votes[winner_votes.party=='democrat'][['state','ratio']]\.groupby('state').mean().sort_values(by='ratio', ascending=False)[:10]
这是共和党方面同样操作的结果。
结论
我们已经分析了美国总统选举的投票数量,每个总统在投票方面的主导地位,以及各州对民主党和共和党的投票情况。但是这篇文章的重点是练习如何将pandas用于数据分析和操作。在数据分析和操作方面,我们做了大量的操作,这个才是我们这篇文章的目的。
最后感谢您的阅读。