3. 比较特朗普和奥巴马的支持率

  1. # pandas的read_html函数可以从网页抓取表格数据
  2. In[31]: base_url = 'http://www.presidency.ucsb.edu/data/popularity.php?pres={}'
  3. trump_url = base_url.format(45)
  4. df_list = pd.read_html(trump_url)
  5. len(df_list)
  6. Out[31]: 14
  1. # 一共返回了14个表的DataFrame,取第一个
  2. In[32]: df0 = df_list[0]
  3. df0.shape
  4. Out[32]: (324, 1906)
  5. In[33]: df0.head(7)
  6. Out[33]:

3. 比较特朗普和奥巴马的支持率 - 图1

  1. # 用match参数匹配table中的字符串
  2. In[34]: df_list = pd.read_html(trump_url, match='Start Date')
  3. len(df_list)
  4. Out[34]: 3
  1. # 通过检查页面元素的属性,用attrs参数进行匹配
  2. In[35]: df_list = pd.read_html(trump_url, match='Start Date', attrs={'align':'center'})
  3. len(df_list)
  4. Out[35]: 1
  1. # 查看DataFrame的形状
  2. In[36]: trump = df_list[0]
  3. trump.shape
  4. Out[36]: (265, 19)
  1. In[37]: trump.head(8)
  2. Out[37]:

3. 比较特朗普和奥巴马的支持率 - 图2

  1. # skiprows可以指定跳过一些行,header参数可以指定列名,用parse_dates指定开始和结束日期
  2. In[38]: df_list = pd.read_html(trump_url, match='Start Date', attrs={'align':'center'},
  3. header=0, skiprows=[0,1,2,3,5], parse_dates=['Start Date', 'End Date'])
  4. trump = df_list[0]
  5. trump.head()
  6. Out[38]:

3. 比较特朗普和奥巴马的支持率 - 图3

  1. # 删除所有值都是缺失值的列
  2. In[39]: trump = trump.dropna(axis=1, how='all')
  3. trump.head()
  4. Out[39]:

3. 比较特朗普和奥巴马的支持率 - 图4

  1. # 统计各列的缺失值个数
  2. In[40]: trump.isnull().sum()
  3. Out[40]: President 258
  4. Start Date 0
  5. End Date 0
  6. Approving 0
  7. Disapproving 0
  8. unsure/no data 0
  9. dtype: int64
  10. # 缺失值向前填充
  11. In[41]: trump = trump.ffill()
  12. trump.head()
  13. Out[41]:

3. 比较特朗普和奥巴马的支持率 - 图5

  1. # 确认数据类型
  2. In[42]: trump.dtypes
  3. Out[42]: President object
  4. Start Date datetime64[ns]
  5. End Date datetime64[ns]
  6. Approving int64
  7. Disapproving int64
  8. unsure/no data int64
  9. dtype: object
  1. # 将前面的步骤做成一个函数,用于获取任意总统的信息
  2. In[43]: def get_pres_appr(pres_num):
  3. base_url = 'http://www.presidency.ucsb.edu/data/popularity.php?pres={}'
  4. pres_url = base_url.format(pres_num)
  5. df_list = pd.read_html(pres_url, match='Start Date', attrs={'align':'center'},
  6. header=0, skiprows=[0,1,2,3,5], parse_dates=['Start Date', 'End Date'])
  7. pres = df_list[0].copy()
  8. pres = pres.dropna(axis=1, how='all')
  9. pres['President'] = pres['President'].ffill()
  10. return pres.sort_values('End Date').reset_index(drop=True)
  11. # 括号中的数字是总统的编号,奥巴马是44
  12. In[44]: obama = get_pres_appr(44)
  13. obama.head()
  14. Out[44]:

3. 比较特朗普和奥巴马的支持率 - 图6

  1. # 获取最近五位总统的数据,输出每位的前三行数据
  2. In[45]: pres_41_45 = pd.concat([get_pres_appr(x) for x in range(41,46)], ignore_index=True)
  3. pres_41_45.groupby('President').head(3)
  4. Out[45]:

3. 比较特朗普和奥巴马的支持率 - 图7

  1. # 确认一下是否有一个日期对应多个支持率
  2. In[46]: pres_41_45['End Date'].value_counts().head(8)
  3. Out[46]: 1990-03-11 2
  4. 1990-08-12 2
  5. 1990-08-26 2
  6. 2013-10-10 2
  7. 1999-02-09 2
  8. 1992-11-22 2
  9. 1990-05-22 2
  10. 2005-01-05 1
  11. Name: End Date, dtype: int64
  1. # 去除重复值
  2. In[47]: pres_41_45 = pres_41_45.drop_duplicates(subset='End Date')
  3. In[48]: pres_41_45.shape
  4. Out[48]: (3695, 6)
  1. # 对数据做简单的统计
  2. In[49]: pres_41_45['President'].value_counts()
  3. Out[49]: Barack Obama 2786
  4. George W. Bush 270
  5. Donald J. Trump 259
  6. William J. Clinton 227
  7. George Bush 153
  8. Name: President, dtype: int64
  9. In[50]: pres_41_45.groupby('President', sort=False).median().round(1)
  10. Out[50]:

3. 比较特朗普和奥巴马的支持率 - 图8

  1. # 画出每任总统的支持率变化
  2. In[51]: from matplotlib import cm
  3. fig, ax = plt.subplots(figsize=(16,6))
  4. styles = ['-.', '-', ':', '-', ':']
  5. colors = [.9, .3, .7, .3, .9]
  6. groups = pres_41_45.groupby('President', sort=False)
  7. for style, color, (pres, df) in zip(styles, colors, groups):
  8. df.plot('End Date', 'Approving', ax=ax, label=pres, style=style, color=cm.Greys(color),
  9. title='Presedential Approval Rating')

3. 比较特朗普和奥巴马的支持率 - 图9

  1. # 上面的图是将数据前后串起来,也可以用支持率对在职天数作图
  2. In[52]: days_func = lambda x: x - x.iloc[0]
  3. pres_41_45['Days in Office'] = pres_41_45.groupby('President') \
  4. ['End Date'] \
  5. .transform(days_func)
  6. In[82]: pres_41_45['Days in Office'] = pres_41_45.groupby('President')['End Date'].transform(lambda x: x - x.iloc[0])
  7. pres_41_45.groupby('President').head(3)
  8. Out[82]:

3. 比较特朗普和奥巴马的支持率 - 图10

  1. # 查看数据类型
  2. In[83]: pres_41_45.dtypes
  3. Out[83]: President object
  4. Start Date datetime64[ns]
  5. End Date datetime64[ns]
  6. Approving int64
  7. Disapproving int64
  8. unsure/no data int64
  9. Days in Office timedelta64[ns]
  10. dtype: object
  1. # Days in Office的数据类型是timedelta64[ns],单位是纳秒,将其转换为整数
  2. In[86]: pres_41_45['Days in Office'] = pres_41_45['Days in Office'].dt.days
  3. pres_41_45['Days in Office'].head()
  4. Out[86]: 0 0
  5. 1 32
  6. 2 35
  7. 3 43
  8. 4 46
  9. Name: Days in Office, dtype: int64
  1. # 转换数据,使每位总统的支持率各成一列
  2. In[87]: pres_pivot = pres_41_45.pivot(index='Days in Office', columns='President', values='Approving')
  3. pres_pivot.head()
  4. Out[87]:

3. 比较特朗普和奥巴马的支持率 - 图11

  1. # 只画出特朗普和奥巴马的支持率
  2. In[88]: plot_kwargs = dict(figsize=(16,6), color=cm.gray([.3, .7]), style=['-', '--'], title='Approval Rating')
  3. pres_pivot.loc[:250, ['Donald J. Trump', 'Barack Obama']].ffill().plot(**plot_kwargs)
  4. Out[88]: <matplotlib.axes._subplots.AxesSubplot at 0x1152254a8>

3. 比较特朗普和奥巴马的支持率 - 图12

更多

  1. # rolling average方法可以平滑曲线,在这个例子中,使用的是90天求平均,参数on指明了滚动窗口是从哪列计算的
  2. In[89]: pres_rm = pres_41_45.groupby('President', sort=False) \
  3. .rolling('90D', on='End Date')['Approving'] \
  4. .mean()
  5. pres_rm.head()
  6. Out[89]: President End Date
  7. George Bush 1989-01-26 51.000000
  8. 1989-02-27 55.500000
  9. 1989-03-02 57.666667
  10. 1989-03-10 58.750000
  11. 1989-03-13 58.200000
  12. Name: Approving, dtype: float64
  1. # 对数据的行和列做调整,然后作图
  2. In[90]: styles = ['-.', '-', ':', '-', ':']
  3. colors = [.9, .3, .7, .3, .9]
  4. color = cm.Greys(colors)
  5. title='90 Day Approval Rating Rolling Average'
  6. plot_kwargs = dict(figsize=(16,6), style=styles, color = color, title=title)
  7. correct_col_order = pres_41_45.President.unique()
  8. pres_rm.unstack('President')[correct_col_order].plot(**plot_kwargs)
  9. Out[90]: <matplotlib.axes._subplots.AxesSubplot at 0x1162d0780>

3. 比较特朗普和奥巴马的支持率 - 图13