Python数据分析(八):农粮组织数据集探索性分析(EDA)

这里我们用FAO(Food and Agriculture Organization)组织提供的数据集,练习一下如何利用python进行探索性数据分析。

探索性数据分析(Exploratory Data Analysis,简称EDA)是指对已有的数据(特别是调查或观察得来的原始数据)在尽量少的先验假定下进行探索,通过作图、制表、方程拟合、计算特征量等手段探索数据的结构和规律的一种数据分析方法,特别是当我们面对大数据时代到来的时候,各种杂乱的“脏数据”,往往不知所措,不知道从哪里开始了解目前拿到手上的数据时候,探索性数据分析就非常有效。

1、导包

我们先导入需要用到的包

%matplotlib inline
%config InlineBackend.figure_format='retina'
import matplotlib as mpl
from matplotlib import pyplot as plt
import seaborn as sns
import pandas as pd
import os,sys
import warnings 
sns.set_context("poster",font_scale=1.3)

接下来,加载数据集

#导入数据
data = pd.read_csv('../数据集/农粮数据/aquastat.csv.gzip',compression='gzip')#compression直接使用磁盘上的压缩文件
data.head()

看一下数据量,

data.shape
#输出结果
(143280, 7)

看一下数据的信息,

data.info()
输出结果
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 143280 entries, 0 to 143279
Data columns (total 7 columns):
country          143280 non-null object
region           143280 non-null object
variable         143280 non-null object
variable_full    143280 non-null object
time_period      143280 non-null object
year_measured    96411 non-null float64
value            96411 non-null float64
dtypes: float64(2), object(5)
memory usage: 7.7+ MB

2、数据切片分析

我们先来看一下variable,variable_full这两列的信息,

#数据切片分析
#看一下variable,variable_full这两列的信息,去掉重复项
data[['variable','variable_full']].drop_duplicates()#drop_duplicate方法是对DataFrame格式的数据,去除特定列下面的重复行。返回DataFrame格式的数据。
#total_area 国土面积(1000公顷)
#arable_land  可耕作面积
#permanent_crop_area 多年生作物面积
#cultivated_area  耕地面积
#percent_cultivated 耕地面积占比
#total_pop 总人口
#rural_pop 农村人口
#urban_pop 城市人口
#gdp 国内生产总值
#gdp_per_capita 人均国内生产总值
#agg_to_gdp 农业,增加国内生产总值
#human_dev_index  人类发展指数
#gender_inequal_index 性别不平等指数
#percent_undernourished 营养不良患病率
#avg_annual_rain_depth 长期平均年降水量
#national_rainfall_index  全国降雨指数

看一下统计了多少国家,

data.country.nunique()
输出结果
199

看一下有多少个时间周期,

data.time_period.nunique()#时间周期
输出结果
12

看一下时间周期有哪些,

time_period = data.time_period.unique()
time_period

我们看一下某一列某个指标的缺失值的个数,比如variable是total_area时缺失值的个数,

data[data.variable=='total_area'].value.isnull().sum()#缺失值个数
输出结果
220

我们通过几个维度来进行数据的分析:

  • 横截面:一个时期内所有国家
  • 时间序列:一个国家随着时间的推移
  • 面板数据:所有国家随着时间的推移(作为数据给出)
  • 地理空间:所有地理上相互联系的国家

我们按照上面的处理继续,现在我们想统计一下对于一个时间周期来说,不同国家在这个周期内的变化情况,

def time_slice(df,time_period):
    df = df[df.time_period == time_period]
    df = df.pivot(index = 'country',columns = 'variable',values='value')
    # 根据列对数据表进行重塑
    # index是重塑的新表的索引名称是什么
    # 第二个columns是重塑的新表的列名称是什么
    # values就是生成新列的值应该是多少
    df.columns.name=time_period
    return df

time_slice(data,time_period[0])

我们也可以按照国家分类,查看某个国家在不同时期的变化,

#按照国家分类,国家在不同时间周期内的变化
countries = data.country.unique()
def country_slice(df,country):
    df = df[df.country == country]
    df = df.pivot(index = 'variable',columns='time_period',values='value')
    df.index.name=country
    return df

country_slice(data,countries[40]).head(10)

我们还可以根据属性,查看不同国家在不同周期内的变化情况,

#对某一个属性或者变量进行分析
def variable_slice(df,variable):
    df = df[df.variable == variable]
    df = df.pivot(index = 'country',columns='time_period',values='value')
    df.index.name='country'
    return df

variable_slice(data,'total_pop').head(10)

我们还可以给定国家和指标,查看这个国家在这个指标上的变化情况,

#给定国家和指标,查看这个国家在这个指标上的变化情况
def time_series(df,country,variable):
    series = df[(df.country == country) & (df.variable == variable)]
    series = series.dropna()[['year_measured','value']]
    
    series.year_measured = series.year_measured.astype(int)#可用于转化dateframe某一列的数据类型
    series.set_index('year_measured',inplace=True)
    series.columns = [variable]
    return series
time_series(data,'Belarus','total_pop')

我们还有region(区域)没有查看,我们来看一下:

data.region.unique()

通过上图可以看出,区域太多,不便于观察,我们可以将一些区域进行合并。减少区域数量有助于模型评估,可以创建一个字典来查找新的,更简单的区域(亚洲,北美洲,南美洲,大洋洲)

simple_regions = {
    'World | Asia':'Asia',
       'Americas | Central America and Caribbean | Central America':'North America',
       'Americas | Central America and Caribbean | Greater Antilles':'North America',
       'Americas | Central America and Caribbean | Lesser Antilles and Bahamas':'North America',
       'Americas | Northern America | Northern America':'North America',
       'Americas | Northern America | Mexico':'North America',
       'Americas | Southern America | Guyana':'South America',
       'Americas | Southern America | Andean':'South America',
       'Americas | Southern America | Brazil':'South America',
       'Americas | Southern America | Southern America':'South America',
       'World | Africa':'Africa',
       'World | Europe':'Europe', 
       'World | Oceania':'Oceania'
}
data.region = data.region.apply(lambda x:simple_regions[x])
print(data.region.unique())
#输出结果
['Asia' 'North America' 'South America' 'Africa' 'Europe' 'Oceania']

我们来看一下数据变化,

data


这样看起来,region数据变得很简洁,我们提取某一个区域来看一下,

#提取单个区域
def subregion(data,region):
    data = data[data.region == region]
    return data

subregion(data,'Asia').head(10)

3、单变量分析

紧接着上面的数据处理,我们重新导入一下包,这次有一些新包,

%matplotlib inline

#plotting
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_context("poster",font_scale=1.3)
import folium  #画世界地图

import os,sys
import numpy as np
import pandas as pd

import pivottablejs
import missingno as msno#缺失值可视化
import pandas_profiling#可以以网页的形式展现给你数据总体概况

msno.matrix(recent,labels=True)#缺失值可视化

我们看一下水资源的情况,

#水资源总量
msno.matrix(variable_slice(data,'exploitable_total'),inline=False,sort='descending')
plt.xlabel('Time period')
plt.ylabel('Country')
plt.title('Missing total exploitable water resources data across countries and time  period \n \n \n')

通过上图可以看出只有一小部分国家报告了可利用的水资源总量,这些国家中只有极少数国家拥有最近一段时间的数据,我们将删除变量,因为这么少的数据点会导致很多问题。

data.loc[~data.variable.str.contains('exploitable'),:]

接下来我们看一下全国降雨指数,

# 全国降水指数(NRI)(毫米/每年)
msno.matrix(variable_slice(data,'national_rainfall_index'),inline=False,sort='descending')
plt.xlabel('Time period')
plt.ylabel('Country')
plt.title('Missing national rainfall index data across countries and time periods \n \n \n')

全国降雨在2002年以后不再报到,所以我们也删除这个数据,

data = data.loc[~(data.variable=='national_rainfall_index')]

我们单独拿出一个洲来进行分析,举例南美洲,我们来看一下数据的完整性,

#看美洲
# 先把数据筛选出来
north_america = subregion(data,'North America')
msno.matrix(msno.nullity_sort(time_slice(north_america,'2013-2017'),sort='descending').T,inline=False)#数据的完整性


通过上图发现,南美洲各国缺失得的数据并不是很多,前几个国家是不缺数据的,我们抽查一下巴哈马(图中倒数第二),看一下它缺少了哪些数据,

msno.nullity_filter(country_slice(data,'Bahamas').T,filter='bottom',p=0.1)


接下来我们探索一下区域之间的关系,看一下缺失值的出现,是不是跟国家之间有关系,我们画一下世界地图,选择区域,然后在这个区域选择某一个指标,看一下它的缺失值的分布情况,颜色越深,缺失值越严重,我们以农业对GDPagg_to_gdp,为指标看一下分布情况,

#颜色越深,缺失值越严重
geo = r'../../数据集/农粮数据/world.json'
null_data = recent['agg_to_gdp'].notnull()*1
map = folium.Map(location=[48,-102],zoom_start=2)
map.choropleth(geo_data=geo,
              data=null_data,
              columns=['country','agg_to_gdp'],
              key_on='feature.properties.name',reset=True,
              fill_color='GnBu',fill_opacity=1,line_opacity=0.2,
              legend_name='Missing agricultural contribution to GDP data 2013-2017')

map

我们也可以指定不同的指标,

def plot_null_map(df,time_period,variable,legend_name=None):
    ts=time_slice(df,time_period).reset_index().copy()#不指明,从0开始
    ts[variable]=ts[variable].notnull()*1
    map = folium.Map(location=[48,-102],zoom_start=2)
    map.choropleth(geo_data=geo,
        data=ts,
        columns=['country',variable],
        key_on='feature.properties.name',reset=True,
        fill_color='GnBu',fill_opacity=1,line_opacity=0.2,
        legend_name=legend_name if legend_name else variable)
    return map
plot_null_map(data,'2013-2017','number_undernourished','Number undernourished id missing')


接下来我们用热力图展示一下,不同指标随着时间的变化情况,颜色越深说明在这个指标上收集到的国家数据越少,反之则越多。

fig,ax = plt.subplots(figsize=(16,16))
sns.heatmap(data.groupby(['time_period','variable']).value.count().unstack().T,ax=ax)
plt.xticks(rotation=45)
plt.xlabel('Time period')
plt.ylabel('Variable')
plt.title('Number of countries with data reported for each variable over time')


通过上图我们知道,刚开始,统计这些指标的国家比较少,随着时间的推移统计这个指标的国家越来越多,可以通过颜色由深到浅的变化看出来,从过上图分析可以知道不同指标国家的重视程度,有些指标也正好相反,国家越来越不重视了。

接下来,我们使用pandas_profiling来对单变量以及多变量之间的关系进行统计一下,

pandas_profiling.ProfileReport(time_slice(data,'2013-2017'))

4、峰度与偏度

这里我们要计算的是,比如

  • 均值,中位数,模式,四分位
  • 标准差、方差、范围、间距范围
  • 偏度、峰度
    首先我们先来看一下数据的描述,
recent[['total_pop','urban_pop','rural_pop']].describe().astype(int) #总人口,城镇人口,农村人口


通过上图我们就可以大体得出我们想要的结果,但是通过看出图表我们发现,rural_pop的最小值是负数,人口统计不应该出现负值,我们继续来看一下,

recent.sort_values('rural_pop')[['total_pop','urban_pop','rural_pop']].head()

我们按照rural_pop从小到大进行排序,发现的确有几个国家的农村人口是负数,

我们再具体看一下这几个国家哪一年的农村人口是负的,我们以Qatar这个国家为例,

time_series(data,'Qatar','total_pop').join(time_series(data,'Qatar','urban_pop')).join(time_series(data,'Qatar','rural_pop'))

人口数目是不可能小于0,所以这说明数据有问题,存在脏数据,如果做分析预测时,要注意将这些脏数据处理一下。

接下来我们看一下偏度,我们规定,

  • 均值<中位数,定为左偏;
  • 均值>中位数,定为有偏;

通过这张图可以看出来,比如total_popmean(36890)>50%(7595),所以是右偏
我们看一下如何计算偏度,

# 计算偏度
import scipy
recent[['total_pop','urban_pop','rural_pop']].apply(scipy.stats.skew)

正态分布的偏度应为零,负偏度表示左偏,正偏表示右偏。

偏度计算完后,我们计算一下峰度,峰度也是一个正态分布,峰度不能为负,只能是正数,越大说明越陡峭,

recent[['total_pop','urban_pop','rural_pop']].apply(scipy.stats.kurtosis)

接下来我们看一下,如果数据分布非常不均匀该怎么办呢,

fig,ax=plt.subplots(figsize=(12,6))
ax.hist(recent.total_pop.values,bins=50)
ax.set_xlabel('Total population')
ax.set_ylabel('Number of countries')
ax.set_title('Distribution of population of countries 2013-2017')

上图是2013-2017年国家总人数的分布,通过上图我们发现,人口量少于200000(不考虑单位)的国家非常多,人口大于1200000的国家非常少,如果我们需要建模的话,这种数据我们是不能要的。这个时候我们应该怎么办呢?

通常,遇到这种情况,使用log变换将其变为正常。对数变换是数据变换的一种常用方式,数据变换的目的在于使数据的呈现方式接近我们所希望的前提假设,从而更好的进行统计推断。

接下来,我们用log转换一下,并看一下它的偏度和峰值,

#偏度
recent[['total_pop']].apply(np.log).apply(scipy.stats.skew)

可以看出偏度下降了很多,减少了倾斜。

#峰度
recent[['total_pop']].apply(np.log).apply(scipy.stats.kurtosis)

可以发现峰度也下降了,接下来我们看一下经过log转换后的数据分布,

def plot_hist(df,variable,bins=20,xlabel=None,by=None,ylabel=None,title=None,logx=False,ax=None):
    if not ax:
        fig,ax=plt.subplots(figsize=(12,8))
    if logx:
        if df[variable].min()<=0:
            df[variable] = df[variable] -df[variable].min()+1
            print('Warning:data<=0 exists,data transformed by %0.2g before plotting' % (-df[variable].min()))
        bins = np.logspace(np.log10(df[variable].min()),np.log10(df[variable].max()),bins)
        ax.set_xscale("log")
    ax.hist(df[variable].dropna().values,bins=bins)
    
    if xlabel:
        ax.set_xlabel(xlabel)
    if ylabel:
        ax.set_ylabel(ylabel)
    if title:
        ax.set_title(title)
    
    return ax
plot_hist(recent,'total_pop',bins=25,logx=True,xlabel='Log of total population',ylabel='Number of countries',
         title='Distribution of total population of countries 2013-2017')

虽然数据还有一些偏度,但是明显好了很多,呈现的分布也比较标准。

5、数据的分析维度

首先我们先来看一下美国的人口总数随时间的变化,

plt.figure(figsize=(10,10))
plt.plot(time_series(data,'United States of America','total_pop'))
plt.xlabel('Year')
plt.ylabel('Population')
plt.title('United States population over time')

接下来,我们查看北美洲每个国家人口总数随着时间的变化,

plt.figure(figsize=(15, 10))
with sns.color_palette(sns.diverging_palette(220,280,s=85,l=25,n=23)):
    north_america = time_slice(subregion(data,'North America'),'1958-1962').sort_values('total_pop').index.tolist()
    for country in north_america:
        plt.plot(time_series(data,country,'total_pop'),label=country)
        plt.xlabel('Year')
        plt.ylabel('Population')
        plt.title('North American populations over time')

    plt.legend(loc=2,prop={'size':10})

这个时候我们发现,一些国家由于人口数量本身就少,所以整个图像显示的不明显,我们可以改变一下参照指标,那我们通过什么标准化?我们可以选择一个国家的最小、平均、中位数、最大值...或任何其他位置。那我们选择最小值,这样我们就能看到每个国家的起始人口上的增长。

plt.figure(figsize=(15, 10))
with sns.color_palette(sns.diverging_palette(220,280,s=85,l=25,n=23)):
    for country in north_america:
        ts=time_series(data,country,'total_pop')
        ts['norm_pop']=ts.total_pop/ts.total_pop.min()*100
        plt.plot(ts['norm_pop'],label=country)
        plt.xlabel('Year')
        plt.ylabel('Percent increase in population')
        plt.title('Percent increase in population from 1960 in North American countries')

    plt.legend(loc=2,prop={'size':10})
人口增长倍率图

我们也可以用热度图来展示,用颜色的深浅来比较大小关系,

north_america_pop = variable_slice(subregion(data,'North America'),'total_pop')
north_america_norm_pop = north_america_pop.div(north_america_pop.min(axis=1),axis=0)*100
north_america_norm_pop = north_america_norm_pop.loc[north_america]
fig,ax = plt.subplots(figsize=(16,12))
sns.heatmap(north_america_norm_pop,ax=ax,cmap=sns.light_palette((214,90,60),input="husl",as_cmap=True))
plt.xticks(rotation=45)
plt.xlabel('Time period')
plt.ylabel('Country,ordered by population in 1960(<-greatest to least->)')
plt.title('Percent increase in population from 1960')

接下来我们分析一下水资源的分布情况,

plot_hist(recent,'total_renewable',bins=50,
         xlabel='Total renewable water resources (10^9 m^3/yr$)',
         ylabel='Number of countries',
         title='Distribution of total renewable water resources,2013-2017')

我们可以进行一下log转换,

plot_hist(recent,'total_renewable',bins=50,
         xlabel='Total renewable water resources (10^9 m^3/yr$)',
         ylabel='Number of countries',logx=True,
         title='Distribution of total renewable water resources,2013-2017')

我们用热度图画一下,

north_america_renew = variable_slice(subregion(data,'North America'),'total_renewable')
fig,ax = plt.subplots(figsize=(16,12))
sns.heatmap(north_america_renew,ax=ax,cmap=sns.light_palette((214,90,60),input="husl",as_cmap=True))
plt.xticks(rotation=45)
plt.xlabel('Time period')
plt.ylabel('Country,ordered by Total renewable water resources in 1960(<-greatest to least->)')
plt.title('Total renewable water resources increase in population from 1960')

6、变量关系可视化展示

连续值可以画成散点图,方便观看,
我们来看一下随着季节变化,人均GDP的变化情况,

data=data.loc[~data.variable.str.contains('exploitable')]
data=data.loc[~(data.variable=='national_rainfall_index')]
plt.figure(figsize=(8,8))
plt.scatter(recent.seasonal_variability,recent.gdp_per_capita)
plt.xlabel('Seasonal variability')
plt.ylabel('GDP per capita ($USD/person)')


不仅可以用散点图,我们还可以Seaborn中的函数JointGrid画出来

def plot_scatter(df,x,y,bins=20,xlabel=None,ylabel=None,title=None,ax=None,logx=False,logy=False):
    if not ax:
        fig,ax=plt.subplots(figsize=(12,8))
    colors = mpl.rcParams['axes.prop_cycle'].by_key()['color']
    if by:
        groups = df.groupby(by)
        for j,(name,group) in enumerate(groups):
            ax.scatter(group[x],group[y],color=colors[j],label=name)
        ax.legend()
    else:
        ax.scatter(df[x],df[y],color=colors[0])
    if logx:
        ax.set_xscale('log')
    if logy:
        ax.set_yscale('log')
    ax.set_xlabel(xlabel if xlabel else x)
    ax.set_ylabel(ylabel if ylabel else y)
    if title:
        ax.set_title(title)
    
    return ax
svr = [recent.seasonal_variability.min(),recent.seasonal_variability.max()]
gdpr = [recent.gdp_per_capita.min(),recent.gdp_per_capita.max()]
gdpbins = np.logspace(*np.log10(gdpr),25)
g = sns.JointGrid(x="seasonal_variability",y="gdp_per_capita",data=recent,ylim=gdpr)
g.ax_marg_x.hist(recent.seasonal_variability,range=svr)
g.ax_marg_y.hist(recent.gdp_per_capita,range=gdpr,bins=gdpbins,orientation="horizontal")
g.plot_joint(plt.hexbin,gridsize=25)
ax = g.ax_joint

g.fig.set_figheight(8)
g.fig.set_figwidth(9)

相关程度:
相关度量两个变量之间的线性关系的强度,我们可以用相关性来识别变量。

现在我们单独拿出来一个指标分析是什么因素与人均GDP的变化有关系,正相关就是积极影响,负相关就是消极影响。

recent_corr = recent.corr().loc['gdp_per_capita'].drop(['gdp','gdp_per_capita'])
def conditional_bar(series,bar_colors=None,color_labels=None,figsize=(13,24),
                   xlabel=None,by=None,ylabel=None,title=None):
    fig,ax = plt.subplots(figsize=figsize)
    if not bar_colors:
        bar_colors = mpl.rcParams['axes.prop_cycle'].by_key()['color'][0]
    plt.barh(range(len(series)),series.values,color=bar_colors)
    plt.xlabel('' if not xlabel else xlabel)
    plt.ylabel('' if not ylabel else ylabel)
    plt.yticks(range(len(series)),series.index.tolist())
    plt.title('' if not title else title)
    plt.ylim([-1,len(series)])
    if color_labels:
        for col,lab in color_labels.items():
            plt.plot([],linestyle='',marker='s',c=col,label=lab)
        lines,labels=ax.get_legend_handles_labels()
        ax.legend(lines[-len(color_labels.keys()):],labels[-len(color_labels.keys()):],loc='upper right')
    plt.close()
    return fig
bar_colors = ['#0055A7' if x else '#2C3E4F' for x in list(recent_corr.values<0)]
color_labels = {'#0055A7':'Negative correlation','#2C3E4F':'Positive correlation'}

conditional_bar(recent_corr.apply(np.abs),bar_colors,color_labels,
               title='Magnitude of correlation with GDP per capita,2013-2017',
               xlabel='|Correlation|')

当我们在画图的时候也可以考虑一下利用bined设置一下区间,比如说连续值我们可以分成几个区间进行分析,这里我们以人均GDP的数量来进行分析,我们可以将人均GDP的数据映射到不同的区间,比如人均GDP比较低,比较落后的国家,以及人均GDP比较高,比较发达的国家,这个也是我们经常需要的操作,

plot_hist(recent,'gdp_per_capita',xlabel='GDP per capita($)',
         ylabel='Number of countries',
         title='Distribution of GDP per capita,2013-2017')

做一下log变换,这里是25个bin

plot_hist(recent,'gdp_per_capita',xlabel='GDP per capita($)',logx=True,
         ylabel='Number of countries',bins=25,
         title='Distribution of GDP per capita,2013-2017')

我们指定一下分割的标准,

capita_bins = ['Very low','Low','Medium','High','Very high']
recent['gdp_bin'] = pd.qcut(recent.gdp_per_capita,5,capita_bins)
bin_ranges = pd.qcut(recent.gdp_per_capita,5).unique()
def plot_hist_div(df,variable,bins=None,xlabel=None,by=None,ylabel=None,title=None,logx=False,ax=None):
    if not ax:
        fig,ax=plt.subplots(figsize=(12,8))
    if logx:
        bins = np.logspace(np.log10(df[variable].min()),np.log10(df[variable].max()),bins)#返回数以对数刻度均匀分布。
        ax.set_xscale("log")
    if by:
        if type(df[by].unique()) == pd.Categorical:
            cats = df[by].unique().categories.tolist()
        else:
            cats = df[by].unique().tolist()
        for cat in cats:
            to_plot = df[df[by] == cat][variable].dropna()
            ax.hist(to_plot,bins=bins)
    else:
        ax.hist(df[variable].dropna().values,bins=bins)
    
    if xlabel:
        ax.set_xlabel(xlabel)
    if ylabel:
        ax.set_ylabel(ylabel)
    if title:
        ax.set_title(title)
    
    return ax
plot_hist_div(recent,'gdp_per_capita',xlabel='GDP per capita($)',logx=True,
         ylabel='Number of countries',bins=25,by='gdp_bin',
         title='Distribution of log GDP per capita,2013-2017')

我们还可以看一下人均GDP较低,落后国家的内部数据,下面我们看一下内部数据分布情况,用boxplot进行画图,

recent[['gdp_bin','total_pop_access_drinking']].boxplot(by='gdp_bin',figsize=(10,10))
plt.title('Distribution of percent of total population with access to drinking water across gdp per capita categories')
plt.xlabel('GDP per capita quintile')
plt.ylabel('Total population of country')

对于这部分的分布,我们还可以统计看一下其他指标,如下图所示,我们还可以看一下洪水的统计信息,

def mult_boxplots(df,variable,category,
                 xlabel=None,ylabel=None,
                 title=None,ylim=None):
    df[[variable,category]].boxplot(by=category,figsize=(10,10))
    
    if xlabel:
        plt.xlabel(xlabel)
    if ylabel:
        plt.ylabel(ylabel)
    if title:
        plt.title(title)
    if ylim:
        plt.ylim(ylim)
mult_boxplots(recent,'flood_occurence','gdp_bin',
             xlabel='GDP per capita quintile')

我们现在总结一下上面用的函数,为了以后方便使用,我们将用到的函数在统计一下,

#某一个时间区域内,各个国家与各个指标之间的关系
def time_slice(df,time_period):
    df = df[df.time_period == time_period]
    df = df.pivot(index = 'country',columns = 'variable',values='value')
    # 根据列对数据表进行重塑
    # index是重塑的新表的索引名称是什么
    # 第二个columns是重塑的新表的列名称是什么
    # values就是生成新列的值应该是多少
    df.columns.name=time_period
    return df

#指定国家,查看各个指标随时间的变化
countries = data.country.unique()
def country_slice(df,country):
    df = df[df.country == country]
    df = df.pivot(index = 'variable',columns='time_period',values='value')
    df.index.name=country
    return df


#指定指标,查看各个国家随着时间的变化
def variable_slice(df,variable):
    df = df[df.variable == variable]
    df = df.pivot(index = 'country',columns='time_period',values='value')
    df.index.name='country'
    return df


#给定国家和指标,查看这个国家在这个指标上的变化情况
def time_series(df,country,variable):
    series = df[(df.country == country) & (df.variable == variable)]
    series = series.dropna()[['year_measured','value']]
    
    series.year_measured = series.year_measured.astype(int)#可用于转化dateframe某一列的数据类型
    series.set_index('year_measured',inplace=True)
    series.columns = [variable]
    return series

#将国家按照各大洲分类
simple_regions = {
    'World | Asia':'Asia',
       'Americas | Central America and Caribbean | Central America':'North America',
       'Americas | Central America and Caribbean | Greater Antilles':'North America',
       'Americas | Central America and Caribbean | Lesser Antilles and Bahamas':'North America',
       'Americas | Northern America | Northern America':'North America',
       'Americas | Northern America | Mexico':'North America',
       'Americas | Southern America | Guyana':'South America',
       'Americas | Southern America | Andean':'South America',
       'Americas | Southern America | Brazil':'South America',
       'Americas | Southern America | Southern America':'South America',
       'World | Africa':'Africa',
       'World | Europe':'Europe', 
       'World | Oceania':'Oceania'
}
data.region = data.region.apply(lambda x:simple_regions[x])


#提取单个区域
def subregion(data,region):
    data = data[data.region == region]
    return data

#查看各个国家总人口的分布情况(数据经过log转换)
def plot_hist(df,variable,bins=20,xlabel=None,by=None,ylabel=None,title=None,logx=False,ax=None):
    if not ax:
        fig,ax=plt.subplots(figsize=(12,8))
    if logx:
        if df[variable].min()<=0:
            df[variable] = df[variable] -df[variable].min()+1
            print('Warning:data<=0 exists,data transformed by %0.2g before plotting' % (-df[variable].min()))
        bins = np.logspace(np.log10(df[variable].min()),np.log10(df[variable].max()),bins)#返回数以对数刻度均匀分布。
        ax.set_xscale("log")
    ax.hist(df[variable].dropna().values,bins=bins)
    
    if xlabel:
        ax.set_xlabel(xlabel)
    if ylabel:
        ax.set_ylabel(ylabel)
    if title:
        ax.set_title(title)
    
    return ax


#提取某个洲的各个国家,查看总人口随时间的变化
plt.figure(figsize=(15, 10))
with sns.color_palette(sns.diverging_palette(220,280,s=85,l=25,n=23)):
    north_america = time_slice(subregion(data,'North America'),'1958-1962').sort_values('total_pop').index.tolist()
    for country in north_america:
        plt.plot(time_series(data,country,'total_pop'),label=country)
        plt.xlabel('Year')
        plt.ylabel('Population')
        plt.title('North American populations over time')

    plt.legend(loc=2,prop={'size':10})


#指定人口基数,查看各个国家在这个基数上人口变化的倍率
plt.figure(figsize=(15, 10))
with sns.color_palette(sns.diverging_palette(220,280,s=85,l=25,n=23)):
    for country in north_america:
        ts=time_series(data,country,'total_pop')
        ts['norm_pop']=ts.total_pop/ts.total_pop.min()*100
        plt.plot(ts['norm_pop'],label=country)
        plt.xlabel('Year')
        plt.ylabel('Percent increase in population')
        plt.title('Percent increase in population from 1960 in North American countries')

    plt.legend(loc=2,prop={'size':10})


#相关性的条形图
def conditional_bar(series,bar_colors=None,color_labels=None,figsize=(13,24),
                   xlabel=None,by=None,ylabel=None,title=None):
    fig,ax = plt.subplots(figsize=figsize)
    if not bar_colors:
        bar_colors = mpl.rcParams['axes.prop_cycle'].by_key()['color'][0]
    plt.barh(range(len(series)),series.values,color=bar_colors)
    plt.xlabel('' if not xlabel else xlabel)
    plt.ylabel('' if not ylabel else ylabel)
    plt.yticks(range(len(series)),series.index.tolist())
    plt.title('' if not title else title)
    plt.ylim([-1,len(series)])
    if color_labels:
        for col,lab in color_labels.items():
            plt.plot([],linestyle='',marker='s',c=col,label=lab)
        lines,labels=ax.get_legend_handles_labels()
        ax.legend(lines[-len(color_labels.keys()):],labels[-len(color_labels.keys()):],loc='upper right')
    plt.close()
    return fig


#将数据分开不同的区域进行相关性分析
def plot_hist_div(df,variable,bins=None,xlabel=None,by=None,ylabel=None,title=None,logx=False,ax=None):
    if not ax:
        fig,ax=plt.subplots(figsize=(12,8))
    if logx:
        bins = np.logspace(np.log10(df[variable].min()),np.log10(df[variable].max()),bins)#返回数以对数刻度均匀分布。
        ax.set_xscale("log")
    if by:
        if type(df[by].unique()) == pd.Categorical:
            cats = df[by].unique().categories.tolist()
        else:
            cats = df[by].unique().tolist()
        for cat in cats:
            to_plot = df[df[by] == cat][variable].dropna()
            ax.hist(to_plot,bins=bins)
    else:
        ax.hist(df[variable].dropna().values,bins=bins)
    
    if xlabel:
        ax.set_xlabel(xlabel)
    if ylabel:
        ax.set_ylabel(ylabel)
    if title:
        ax.set_title(title)
    
    return ax


#指标的不同类别进行boxplot分析
def mult_boxplots(df,variable,category,
                 xlabel=None,ylabel=None,
                 title=None,ylim=None):
    df[[variable,category]].boxplot(by=category,figsize=(10,10))
    
    if xlabel:
        plt.xlabel(xlabel)
    if ylabel:
        plt.ylabel(ylabel)
    if title:
        plt.title(title)
    if ylim:
        plt.ylim(ylim)

关于农粮组织数据的探索性分析到这里就结束了,希望大家能动手做一下。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 践行第49天 25 February 2019 你早点回,最近偷猪的事比较多,我担心你出事。 但凡不快乐,都是自找...
    花颜徐徐来阅读 244评论 0 0
  • 为什么, 上天这么宠爱青海? 给她一个超大的蓝宝石! 为什么, 上天这么宠爱青海? 给她一面天空之镜! 为什么, ...
  • 周日午后,刚刚放下手里的电话,正在给刚刚的面试者写评价。刚刚写到『对Linux的基本IO模型理解不深』这句的时候,...
    创造new_world阅读 1,235评论 1 5
  • 第一讲回顾:拜访客户前需要设立拜访目标,同时,最好设立一个主目标和一个次目标。根据客户公司的规模、接洽人职位、合作...
    ZK_刘小年阅读 590评论 4 12
  • 女性的社会贫困,是因为在家庭、社会、国家和市场之间,都没有获得足够的生存帮助。家庭保障体系,社会福利体系,就业体系...
    令村阅读 203评论 0 0