世界各州的贫富差距分析

讨论问题:
一、很多媒体报道美国在过去一些年间贫富差距扩大。这里我们分析全球数据,运用数据分析全球各个州之间在过去20年间的贫富差距是扩大,减小还是维持不变。
二、以亚洲与南美数据为例分析,如果A组的平均值大于B组,是否说明最大值在A组中
1、首先,将国家和地区数据在Github上取下来:

url = "https://raw.githubusercontent.com/cs109/2014_data/master/countries.csv" s = StringIO.StringIO(requests.get(url).content) countries = pd.read_csv(s) print countries.head() CountryRegion 0AlgeriaAFRICA 1AngolaAFRICA 2BeninAFRICA 3BotswanaAFRICA 4BurkinaAFRICA

然后将国家的人均收入数据从https://www.gapminder.org/data/documentation/gd001/这个网站上取下来
income = pd.read_excel('.../indicator gapminder gdp_per_capita_ppp.xlsx',sheetname = "Data") print income.head() GDP per capita180018011802180318041805 0AbkhaziaNaNNaNNaNNaNNaNNaN 1Afghanistan603.0603.0603.0603.0603.0603.0 2Akrotiri and DhekeliaNaNNaNNaNNaNNaNNaN 3Albania667.0667.0668.0668.0668.0668.0 4Algeria716.0716.0717.0718.0719.0720.0

有些国家没有数据,删除缺失项
income = income.dropna(how='all')
我们想要画出某年各个国家的人均收入分布图,分布图用直方图来表示是最合适的,这里将年份作为行名更容易画各年的直方图
income.index=income[income.columns[0]] # 国家作为序号 income = income.drop(income.columns[0], axis = 1) income.columns = map(lambda x: int(x), income.columns) # 将列名中的年份数据转为int类型,为了直接取年份 income = income.transpose()#转置 print income.head() GDP per capitaAfghanistanAlbaniaAlgeriaAndorraAngola\ 1800603.0667.0716.01197.0618.0 1801603.0667.0716.01199.0620.0 1802603.0668.0717.01201.0623.0 1803603.0668.0718.01204.0626.0 1804603.0668.0719.01206.0628.0

接下来画直方图:
year = 2000 plt.hist(income.ix[year].values, bins = 20) plt.title('Year: %i' % year) plt.xlabel('人均收入') plt.ylabel('频数') plt.show()

世界各州的贫富差距分析
文章图片
image.png
可以看出人均一万美金以下的国家最多,各个国家之间的贫富差距相当大,那1万美金以下究竟是怎么分布的看不出来,将收入取log则能区分出来:
plt.hist(np.log10(income.ix[year].dropna().values), bins = 20) plt.title('Year: %i' % year) plt.xlabel('人均收入 (log10)') plt.ylabel('频数') plt.show()

世界各州的贫富差距分析
文章图片
image.png
可以看出2000年时人均10000美金的国家是最多的,人均一万美金以下的分布也较广,还有人均几百美金的
接下来看各州之间的贫富差距:
2、将Country表格与income表格合并,观察两个表格可以看出共同的参数是国家名,所以以这个为主键进行合并
def mergeByYear(year): #取出收入数据 data = https://www.it610.com/article/pd.DataFrame(income.ix[year].values, columns=['Income']) # 拿到income的列名,作为新dataframe的Country列 data['Country'] = income.columns joined = pd.merge(data, countries, how="inner", on=['Country']) return joined print mergeByYear(2000).head() IncomeCountryRegion 0962.0AfghanistanASIA 15305.0AlbaniaEUROPE 29885.0AlgeriaAFRICA 331662.0AndorraEUROPE 43387.0AngolaAFRICA

3、画出各州的人均收入分布,这里采用箱形图来表现,箱形图可以表示数据的多种特征,如下图所示:
世界各州的贫富差距分析
文章图片
image.png 世界各州的贫富差距分析
文章图片
image.png 世界各州的贫富差距分析
文章图片
image.png 世界各州的贫富差距分析
文章图片
image.png 世界各州的贫富差距分析
文章图片
image.png 世界各州的贫富差距分析
文章图片
image.png 世界各州的贫富差距分析
文章图片
image.png 可以看出亚洲和非洲人均收入的趋势是向上的,亚洲相比上升更多,其他州则基本保持不变。同时可以看出非洲和亚洲的奇异值相比较多,并且箱型图越来越长,说明亚洲和非洲各个国家之间的贫富差距较大,这种差距从20世纪60年代持续至今。
接下来讨论问题二:
1、如果有两组数据X和Y,都大致服从正态分布,X和Y的标准差都为1,但是X的均值大于Y的均值,计算Pr(X > a)/Pr(Y > a) 。
列出该表达式的函数:
diff是X的均值,Y的均值为0
def ratioNormals(diff,a): X = scipy.stats.norm(loc = diff,scale = 1) Y = scipy.stats.norm(loc = 0,scale = 1) return X.sf(a)/Y.sf(a) #sf是生存函数,即求X>a的概率

用不同的均值差来计算概率比值:
diffs = np.linspace(0,5,50) aa = range(2,6) for a in aa: ratios = [ratioNormals(diff, a) for diff in diffs] plt.plot(diffs,ratios) plt.legend(["a={}".format(a) for a in aa], loc=0); plt.xlabel('Diff'); plt.ylabel('Pr(X>a) / Pr(Y>a)'); plt.title('不同差值下Pr(X>a)与Pr(Y>a)的概率比'); plt.yscale('log') plt.show()

世界各州的贫富差距分析
文章图片
image.png
可以看出,在正太分布下,当X的均值大于Y时,Pr(X>a)>Pr(Y>a),并且差值越大,两者之间的差距也越大。
2、考虑亚洲和南美的人均收入分布,计算这两个州的人均收入,哪个州的人均收入更多
利用mergeByYear函数拿到地区、国家、收入的dataframe,按照地区分组聚合,计算平均收入,可以看出亚洲的平均收入远大于南美。
merged = mergeByYear(2012).groupby('Region', as_index=False).mean() merged = merged.loc[(merged.Region == "ASIA") | (merged.Region == "SOUTH AMERICA")] merged.Income = np.round(merged.Income, 2)#保留小数点两位 print merged RegionIncome 1ASIA23500.43 5SOUTH AMERICA13015.75

3、那接下来算一下人居收入大于10000美金的国家占所在州的比例,,再次看一下上面的结论是否正确。构造一个计算国家比例的函数:
def ratioCountries(groupedData, a): #下面key指的是Region,group指代的是key所对应的分组,必须要有key指定才能找到分组信息,这里求得是各州中人均收入大于10000美金的国家占所在州国家的比例 prop = [len(group.Income[group.Income >= a]) / float(len(group.Income.dropna())) for key, group in groupedData] z = pd.DataFrame(groupedData.mean().index, columns = ['Region']) z['Mean'] = np.round(groupedData.mean().values,2) z['P(X > %g)' % a] = np.round(prop, 4) return z df = mergeByYear(2012).groupby('Region') df_ratio = ratioCountries(df, 1e4) print df_ratio RegionMeanP(X > 10000) 0AFRICA5601.220.2000 1ASIA23500.430.5676 2EUROPE30738.190.8571 3NORTH AMERICA16036.650.6500 4OCEANIA10481.150.3077 5SOUTH AMERICA13015.750.7500

把南美和亚洲提取出来:
df_ratio = df_ratio[(df_ratio.Region == 'ASIA') | (df_ratio.Region == 'SOUTH AMERICA')] print df_ratio RegionMeanP(X > 10000) 1ASIA23500.430.5676 5SOUTH AMERICA13015.750.7500

可以看出人均大于10000美金的国家在所在州所占比例,亚洲小于南美,这与上面的结论不一致。
4、上面可以看出亚洲国家之间的贫富差距有多大,接下来考虑一个问题,如果考虑各国人口数量,那人均收入是否会发生改变呢
比如我国和日本,我国的人均GDP8000美金,日本人均GDP35000美金,按照上面的算法,两国人均收入(8000+32000)/2,我国人均收入瞬间提升到20000美金。如果考虑两国人口呢,假设中日是一个国家,中国人口14亿,日本1亿3000万,那平均收入的计算方法为:

世界各州的贫富差距分析
文章图片
image.png
N为人口,I为本国的人均收入,则上述中日两国修正后的人均收入为(8000 14+320001.3)/(14+1.3)≈10000
如此看来,计算了各国人口,这个平均值才能代表亚洲的真实水平,那接下来修正一下这个数据。这里可以将上述表达式进行拆分,只需要求出各国总收入除以整个州的人口,然后求和便能求出平均收入。
首先导入人口数据,并对其进行预处理:
#首先导入人口数据 population = pd.read_excel('.../indicator_total population with projections.xlsx',sheetname = "Data") print population.head() Total population10861100129013001348134913511377\ 0AbkhaziaNaNNaNNaNNaNNaNNaNNaNNaN 1AfghanistanNaNNaNNaNNaNNaNNaNNaNNaN 2Akrotiri and DhekeliaNaNNaNNaNNaNNaNNaNNaNNaN 3AlbaniaNaNNaNNaNNaNNaNNaNNaNNaN 4AlgeriaNaNNaNNaNNaNNaNNaNNaNNaN 1413...2006200720082009\ 0NaN...NaNNaNNaNNaN 1NaN...28420974.029145841.029839994.030577756.0 2NaN...NaNNaN15700.0NaN 3NaN...3156607.03169665.03181397.03192723.0 4NaN...33391954.033906605.034428028.034950168.0

删除全部是NAN的国家,按照上面的方法将数据进行处理,方便下面进行分组聚合。
population = population.dropna(how='all') population = population.rename(columns = {'Total population':'Country'})#重命名 #把国家列设为index population.index=population[population.columns[0]] population = population.drop(population.columns[0], axis = 1) population.columns = map(lambda x: int(x), population.columns)#将年份改为int类型 population = population.transpose()

接下来我们想把人口数据这个表格与mergeByYear这个包含人均收入,国家,地区的表格进行合并.
#将其与income,国家,地区按照国家这个主键进行合并 def mergeByYearWithPop(year): merged_df = mergeByYear(year) pop_df = pd.DataFrame(population.ix[year].values, columns=['Population']) pop_df['Country'] = population.columns joined = pd.merge(merged_df,pop_df,how="inner", on=['Country']) #按照刚才的分析求调整后的收入,再定义一个函数,这里传入的是按地区分割的groupby对象 def func(df): totlePop = df.sum()['Population'] df['AdjustedIncome'] = df.Income * df.Population / float(totlePop) df.AdjustedIncome = np.round(df.AdjustedIncome, 2) return df return joined.groupby('Region').apply(func) print mergeByYearWithPop(2012).head() IncomeCountryRegionPopulationAdjustedIncome 01893.0AfghanistanASIA33397058.015.66 19811.0AlbaniaEUROPE3227373.053.43 212779.0AlgeriaAFRICA36485828.0489.77 341926.0AndorraEUROPE87518.06.19 47230.0AngolaAFRICA20162517.0153.13

得到这个dataframe后,将最后一列按照Region求和便能得出调整后的平均收入,接下来求按国家计算的平均收入和考虑人口数量的平均收入
mergeWithPop_df = mergeByYearWithPop(2012).groupby('Region').sum() df1 = mergeByYear(2012).groupby('Region').mean() mergeWithPop_df.Income = mergeByYear(2012).groupby('Region').mean().Income mergeWithPop_df = mergeWithPop_df.ix[['ASIA', 'SOUTH AMERICA']] print mergeWithPop_df IncomePopulationAdjustedIncome Region ASIA23500.4324324.036626e+099717.54 SOUTH AMERICA13015.7500004.005576e+0814551.71

【世界各州的贫富差距分析】这里可以看出,亚洲在调整前的平均收入大于南美,而当考虑了人口后,平均收入小于南美。
综上所述,如果A与B都服从正太分布,那当A的平均值大于B时,Pr(X>a)>Pr(Y>a),而当讨论两个州人均收入大于10000美金的国家所占比例时得出了相反的结论,这是因为国家的人均收入不遵循正太分布。
最后考虑了各国的总人口,将州人均收入进行了调整,得出在调整前亚洲的人均收入大于南美,然后调整后反而小了,这说明亚洲国家之间的贫富差距相当大,太多奇异值使得按照国家计算时与按照人口计算时偏差太大,而南美各国间的贫富差距较小,两个数据之间差距不太大。

    推荐阅读