数据可视化练习


#!/usr/bin/env python
# coding: utf-8

# In[1]:


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('city_temperature.csv',dtype={'State':object})


# In[2]:


data['AvgTemperature'] = (data['AvgTemperature']-32)/1.8


# In[3]:


data.isnull().value_counts()


# #### 【练习1】 绘制[10,20,30,100,110,120,130,140]对应的箱线图,并自行计算各值,与绘制结果进行对比,发现什么问题?

# In[4]:


test_df = pd.DataFrame([10,20,30,100,120,130,140])
test_df.boxplot()


##### 【练习2】 修改上题数据,使得上方出现两个异常值,下方出现一个异常值。

# In[5]:


test_df = pd.DataFrame([-150,20,30,100,120,130,290])
test_df.boxplot()


# #### 【练习3】 绘制city_temperature.csv里面“Year”列数据对应的箱线图,有没有异常值?这个异常值的产生原因可能是什么?

# In[6]:


data[['Year']].boxplot()


# #### 【练习4】 按年统计1995-2019年之间7月巴黎市的气温平均值,并绘制对应的箱线图。

# In[7]:


data.query('City=="Paris" and Year>=1995 and Year<=2019 and Month==7').groupby(by='Year')['AvgTemperature'].agg(['mean']).boxplot()


# #### 【练习5】 将小于-70℃的AvgTemperature数据改为NaN。

# In[17]:


data.loc[data['AvgTemperature']<-70, 'AvgTemperature'] = np.nan


# In[10]:


data.head()


# #### 【练习6】 删除巴黎市1995年的所有NaN记录。

# In[18]:


data.query('City=="Paris" and Year==1995 and AvgTemperature.isnull()')


# In[19]:


data.drop(data.query('City=="Paris" and Year==1995 and AvgTemperature.isnull()').index,axis=0, inplace=True)


# In[21]:


data.query('City=="Paris" and Year==1995 and AvgTemperature.isnull()')


# In[22]:


data.query('City=="Paris" and Year==1995')


# #### 【练习7】 删除巴黎市2008年的所有NaN记录(用一条代码实现)。

# #### 同【练习6】

# #### 【练习8】 分别使用向前、向后、平均值填充方式处理巴黎市2018年7月的NaN数据。

# In[23]:


data.query('City=="Paris" and Year==2018 and Month==7')


# In[24]:


paris_2018_7 = data.query('City=="Paris" and Year==2018 and Month==7').copy(deep=True)


# In[25]:


paris_2018_7


# In[26]:


data.drop(paris_2018_7.index, axis=0, inplace=True)


# In[27]:


data.query('City=="Paris" and Year==2018 and Month==7')


# In[28]:


paris_2018_7['AvgTemperature'].fillna(method="ffill", limit=1, inplace=True)


# In[29]:


paris_2018_7


# In[30]:


paris_2018_7['AvgTemperature'].fillna(method="bfill", limit=1, inplace=True)


# In[31]:


paris_2018_7


# In[32]:


paris_2018_7['AvgTemperature'].fillna(paris_2018_7['AvgTemperature'].mean(), inplace=True)


# In[33]:


paris_2018_7


# In[34]:


data = data.append(paris_2018_7)


# In[35]:


data.query('City=="Paris" and Year==2018 and Month==7')



# #### 【练习9】 将“Month”列数据由数字月份改为英文缩写月份:Jan、Feb、Mar、Apr、May、Jun、Jul、Aug、Sept、Oct、Nov、Dec。

# In[36]:


months = {1:'Jan',2:'Feb',3:'Mar',4:'Apr',5:'May',6:'Jun',7:'Jul',8:'Aug',9:'Sept',10:'Oct',11:'Nov',12:'Dec'}
data['Month'].replace(months, inplace=True)


# In[37]:


data


# #### 【练习10】 将区域为“北美洲”的国家名改为中文名,要求使用map()实现。

# In[38]:


data['Region'].unique()


# In[39]:


data.query('Region=="North America"')['Country'].unique()


# In[43]:


all_countries = data['Country'].unique()


# In[45]:


country_map = {}


# In[46]:


for name in all_countries:
    country_map[name] = name


# In[48]:


country_map['Canada'] = '加拿大'
country_map['Mexico'] = '墨西哥'
country_map['US'] = '美国'


# In[50]:


data['Country'].map(country_map)


# In[51]:


data['Country'] = data['Country'].map(country_map)


# In[52]:


data.query('Region=="North America"')['Country'].unique()


# #### 【练习11】 将区域为“北美洲”的国家名改为中文名,要求使用replace()实现。

# In[57]:


data['Country'].replace({'Singapore':'新加坡'}, inplace=True)


# In[58]:


data.query('Region=="Asia"')['Country'].unique()


# #### 【练习12】 按季度统计中东地区的气温平均值。

# In[75]:


data['日期'] = data['Year'].astype(str) + '/' +data['Month'].astype(str) + '/' + data['Day'].astype(str) 


# In[76]:


data['日期'] = pd.to_datetime(data['日期'], format='%Y/%m/%d', errors = "coerce")


# In[77]:


data.set_index(['日期'], inplace=True)


# In[78]:


data.head()


# In[79]:


data.query('Region=="Middle East"')['AvgTemperature'].resample("Q").mean()


# #### 【练习13】 按年统计全球的气温平均值。

# In[80]:


data['AvgTemperature'].resample('A').mean()


# #### 【练习14】 按年统计1995-2019年之间7月London市的气温平均值。

# In[81]:


data.query('Year>=1995 and Year<=2019 and Month==7')['AvgTemperature'].resample('A').mean()


# In[82]:


data.query('Year>=1995 and Year<=2019 and Month==7').groupby('Year')['AvgTemperature'].mean()


# In[83]:


data.query('Year>=1995 and Year<=2019').groupby('Year')['AvgTemperature'].mean()


# #### 【练习15】 按星期统计2020年1、2、3、4月Tokyo市的气温平均值。

# In[84]:


data.query('Year==2020 and Month in [1,2,3,4]')['AvgTemperature'].resample('W').mean()


# ### 5.5.4练习

# #### 【练习16】 绘制1995-2019年期间全球平均气温变化趋势,

# In[6]:


plt.rcParams['font.sans-serif'] = ['SimHei']            # 正确实现中文
plt.rcParams['axes.unicode_minus'] = False


# In[14]:


fig_data = data.query('Year>=1995 and Year<=2019 and AvgTemperature>-72')[['Year','AvgTemperature']].groupby(by='Year').mean()
plt.figure()
x = np.array(fig_data.index)
y = np.array(fig_data['AvgTemperature'])
plt.plot(x, y, label='全球平均气温')
plt.title('1995-2019年全球年均气温变化')
plt.xlabel('年份')
plt.ylabel('年均气温')
plt.tick_params(axis='both',which='major',labelsize=8)
plt.xticks(np.arange(min(x), max(x)+1, 3))
plt.legend()
plt.savefig("5-26.png",dpi=600,bbox_inches='tight')
plt.show()


# #### 【练习17】 基于图5-26,在同一张图里面绘制1995-2019年期间全球平均气温和最低气温变化趋势(注意删除数据中日均气温异常值),发现什么问题?

# In[15]:


fig_data = data.query('Year>=1995 and Year<=2019 and AvgTemperature>-72')[['Year','AvgTemperature']].groupby(by='Year').agg({'AvgTemperature':['mean','min']})
plt.figure()
x = np.array(fig_data.index)
y_mean = np.array(fig_data[('AvgTemperature','mean')])
y_min = np.array(fig_data[('AvgTemperature','min')])
plt.plot(x, y_mean, label='全球平均气温')
plt.plot(x, y_min, label='全球最低气温')
plt.title('1995-2019年全球年均气温变化')
plt.xlabel('年份')
plt.ylabel('气温')
plt.tick_params(axis='both',which='major',labelsize=8)
plt.xticks(np.arange(min(x), max(x)+1, 3))
plt.legend()
plt.savefig("5-26-2.png",dpi=600,bbox_inches='tight')
plt.show()


# In[12]:


fig_data =data.query('Year>=1995 and Year<=2019 and AvgTemperature>-72')[['Year','AvgTemperature']].groupby(by='Year').agg({'AvgTemperature':["mean","min"]})
fig_data


# #### 【练习18】 基于上题,绘制图双坐标系图表(配色自行指定)。

# In[6]:


fig_data = data.query('Year>=1995 and Year<=2019 and AvgTemperature>-72')[['Year','AvgTemperature']].groupby(by='Year')
mean_data = fig_data.agg({'AvgTemperature':'mean'})
x = np.array(mean_data.index)
mean_y = np.array(mean_data['AvgTemperature'])
min_data = fig_data.agg({'AvgTemperature':'min'})
x = np.array(mean_data.index)
min_y = np.array(min_data['AvgTemperature'])
fig = plt.figure(figsize=(14,6))
ax1 = fig.add_subplot(111)
ax1.set_xlabel('年份')
ax1.set_ylabel('日均气温')
ax1.set_ylim(14.5,17)
ax1.margins(x=0.01)
plt.title('1995-2019年期间世界气温变化趋势')
ax1.bar(x, height=mean_y, color='cadetblue', width=0.5, label='平均日均气温')
ax1.legend(loc=2)
ax2 = ax1.twinx()
ax2.margins(x=0.01)
ax2.plot(x, min_y, color='purple', label='最低日均气温')

ax2.legend()
plt.savefig("5-27.png",dpi=600,bbox_inches='tight')


# #### 【练习19】 查询2019年年度平均气温创历史新高的国家所属各洲的比例,绘制图饼图。

# In[3]:


year_avg_data = data.query('Year !=2020 and AvgTemperature>-50').groupby(by=['Region','Country','Year']).mean()['AvgTemperature'].unstack()


# In[4]:


year_avg_data 


# In[5]:


year_avg_data.apply(lambda x: x.idxmax()==2019,axis = 1).value_counts()


# In[7]:


year_avg_data[year_avg_data.apply(lambda x: x.idxmax()==2019,axis = 1)]


# In[8]:


x = year_avg_data[year_avg_data.apply(lambda x: x.idxmax()==2019, axis=1)].groupby(by='Region')[2019].count()


# In[12]:


x


# In[11]:


fig_data = year_avg_data[year_avg_data.apply(lambda x: x.idxmax()==2019, axis=1)].groupby(by='Region')[2019].count()
plt.figure(figsize=(8,8))
explode = [0.05 for i in range(len(fig_data))]
plt.pie(fig_data.values, labels=fig_data.index, explode=explode, autopct='%.0f%%',startangle=100)
plt.savefig("5-28.png",dpi=600,bbox_inches='tight')
plt.show()


# #### 【练习20】

# In[22]:


fig_data = year_avg_data[year_avg_data.apply(lambda x: x.idxmax()==2019, axis=1)].groupby(by='Region')[1995].count()
total_country = fig_data.sum()
explode = [0.05 for i in range(len(fig_data))]
fig, ax = plt.subplots(figsize=(8,8), subplot_kw=dict(aspect="equal"))
wedges, texts = ax.pie(fig_data, wedgeprops=dict(width=0.5), startangle=0)

bbox_props = dict(boxstyle="square,pad=0.3", fc="w", ec="k", lw=0.72)
kw = dict(arrowprops=dict(arrowstyle="-"),
          bbox=bbox_props, zorder=0, va="center")

for i, p in enumerate(wedges):
    ang = (p.theta2 - p.theta1)/2. + p.theta1
    y = np.sin(np.deg2rad(ang))
    x = np.cos(np.deg2rad(ang))
    horizontalalignment = {-1: "right", 1: "left"}[int(np.sign(x))]
    connectionstyle = "angle,angleA=0,angleB={}".format(ang)
    kw["arrowprops"].update({"connectionstyle": connectionstyle})
    ax.annotate(fig_data.index[i] + ': '+str(fig_data.iloc[i]) + ' ('+ '%.0f%%' % (fig_data.iloc[i]*100/total_country)+')', xy=(x, y), xytext=(1.15*np.sign(x), 1.2*y),
                horizontalalignment=horizontalalignment,fontsize=16, **kw)
plt.savefig("5-29.png",dpi=600,bbox_inches='tight')
plt.show()


# #### 【练习21】 使用plt.text()方法)。

# In[23]:


data1 = data.query('City=="Guangzhou" and Year>=2000 and Year <=2019').copy()
bins = [-100,15,30,100]
labels = ['低温天数','常温天数','高温天数']
data1['分类'] = pd.cut(data1['AvgTemperature'],bins = bins, labels = labels)
data1_group = data1.groupby(by=['Year','分类']).agg({'AvgTemperature':'count'})


# In[24]:


data1_group = data1_group['AvgTemperature'].unstack()
data1_group.columns = data1_group.columns.to_list()
data1_group = data1_group/365


# In[25]:


plt.figure(figsize=(16,6))
plt.title("2000-2019年广州市气温分组占比")
plt.xlabel('年份')
plt.ylabel('比率')
plt.xticks(data1_group.index)
plt.margins(x=0.01)
plt.bar(x=data1_group.index, height= data1_group['低温天数'], label='低温天数', width=0.4)
plt.bar(x=data1_group.index, height= data1_group['常温天数'], bottom = data1_group['低温天数'], label='常温日数', width=0.4)
plt.bar(x=data1_group.index, height= data1_group['高温天数'], bottom = data1_group['低温天数']+data1_group['常温天数'], label='高温日数', width=0.4)
plt.legend(loc='upper right')
for i in data1_group.index:
    plt.text(i, data1_group['低温天数'][i]/2*0.8,"{:.0%}".format(data1_group['低温天数'][i]),size=12,horizontalalignment="center",color='white')
    plt.text(i, data1_group['低温天数'][i]+data1_group['常温天数'][i]/2*0.9,"{:.0%}".format(data1_group['常温天数'][i]),size=12,horizontalalignment="center",color='black')
    plt.text(i, data1_group['低温天数'][i]+data1_group['常温天数'][i]+data1_group['高温天数'][i]/2*0.9,"{:.0%}".format(data1_group['高温天数'][i]),size=12,horizontalalignment="center",color='white')
plt.savefig('5-30.png', dpi=600, bbox_inches='tight')


# #### 【练习22】 全球变暖对于高纬度国家(即靠近南极和北极的国家)影响更为显著。以北欧Finland(芬兰)为例,按年统计1995-2019年期间日均气温低于0℃的天数,并绘制图5-31。

# In[26]:


fig_data =data.query('Country=="Finland" and AvgTemperature>-70  and AvgTemperature<0 and Year<2020')[['Year','AvgTemperature']].groupby('Year')['AvgTemperature'].count()
plt.figure(figsize=(10,6))
plt.margins(x=0.01)
plt.xlabel('年份')
plt.ylabel('天数')
plt.xticks(np.array(fig_data.index), rotation=45)
plt.title('1995-2019期间芬兰日均气温小于0℃的天数')
plt.bar(x=np.array(fig_data.index), height=np.array(fig_data.values), width=0.5, color='crimson', label='Finland')
plt.legend()
plt.savefig("5-31.png",dpi=600,bbox_inches='tight')


# #### 【练习23】 统计2015-2019期间北欧四国(Finland、Sweden、Norway、Denmark)日均气温低于0℃的天数

# In[16]:


fig_data = data.query('Country in ["Finland","Sweden","Denmark", "Norway"] and AvgTemperature>-70 and Year>=1995 and AvgTemperature<0 and Year<=2019')[['Country','Year','AvgTemperature']].groupby(by=['Country','Year'])['AvgTemperature'].count().unstack()
fig_data.iloc[:,-1] = fig_data.iloc[:,-1]/fig_data.iloc[:,0]
for i in range(-5,-1):
    fig_data.iloc[:,i] = fig_data.iloc[:,i]/fig_data.iloc[:,0]


# In[21]:


import matplotlib.ticker as mtick
LARGE_SIZE=14
plt.figure(figsize=(12,6))
x1 = np.arange(len(fig_data.index))
width=0.15
plt.gca().yaxis.set_major_formatter(mtick.PercentFormatter(1))
plt.bar(x1-2*width, height=fig_data.iloc[:,-5], width=width)
plt.bar(x1-1*width, height=fig_data.iloc[:,-4], width=width)
plt.bar(x1+0*width, height=fig_data.iloc[:,-3], width=width)
plt.bar(x1+1*width, height=fig_data.iloc[:,-2], width=width)
plt.bar(x1+2*width, height=fig_data.iloc[:,-1], width=width)
plt.xticks(x1,np.array(fig_data.index))
plt.xlabel('国家')
plt.ylabel('百分比(%)')
plt.title('2015-2019期间北欧四国低温天气日数与1995年日数之比示意图')
plt.grid()
plt.rc('ytick', labelsize=LARGE_SIZE)
plt.rc('xtick', labelsize=LARGE_SIZE)
plt.rc('font', size=LARGE_SIZE)
plt.legend(fig_data.columns[-5:])
plt.savefig("5-32.png",dpi=600,bbox_inches='tight')


# In[14]:


fig_data = data.query('Country in ["Finland","Sweden","Denmark", "Norway"] and AvgTemperature>-50 and Year>=1995 and AvgTemperature<0 and Year<=2019')[['Country','Year','AvgTemperature']].groupby(by=['Country','Year'])['AvgTemperature'].count().unstack()


# In[15]:


fig_data


# In[5]:


fig_data.iloc[:,-1] = fig_data.iloc[:,-1]/fig_data.iloc[:,0]


# In[18]:


fig_data


# In[7]:


for i in range(-5,-1):
    fig_data.iloc[:,i] = fig_data.iloc[:,i]/fig_data.iloc[:,0]


# In[8]:


fig_data


# In[4]:


fig_data.iloc[:,0]