统计02:怎样描绘数据

  • 时间:
  • 浏览:3

作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载。

统计最结速的主要任务好多好多 我描述数据。正如亲戚亲戚亲戚朋友在统计概述中提到的,群体的数据完后 蕴含大量的数字,往往你可不都能否 读起来头昏脑涨。电影《美丽心灵》中,数学家纳什不自觉地沉浸在一串数字中。完后 的电影桥段一个劲让观众感到惭愧。但真相是,每此人 的注意力和短期记忆都很有限,那末 集中在很大量的信息。数据描述好多好多 我要用一定的依据来提取大量信息,从而你可不都能否 更容易明白数据的含义。数据描述的依据可不都能否 分为两大门类,即群体参数和数据绘图。两者都起到了比较复杂信息作用,从而让数据变得更加易读。

群体参数

群体参数是用一些数字来表示群体的形态。亲戚亲戚亲戚朋友在统计概述中完后 介绍了有一一一还还有一个多多 群体参数,群体平均值和群体方差。群体平均值(population mean)反映群体总体请况,定义如下:

$$\mu=\frac{1}{N} \sum_{i=0}^N x_i$$

群体方差(population variance)反映群体的离散请况,定义如下: 

$$\sigma^2=\frac{1}{N} \sum_{i=0}^N (x_i - \mu)^2$$

方差的平方根,即[$\sigma$],称为群体标准差(standard deviation)。从物理的高度上来看,平均值和标准差所带的单位,都和原始数据相同。在多数统计案例中,大每段的群体数据会落在平均值加减有一一一还还有一个多多 标准差的范围内。

还有一些参数要通过对群体成员进行排序不能获得。比如群体的最大值(max)和最小值(min)。在这些类参数中,还一个劲会用到中位数(median)和四分位数(quartile)。对成员进行排序后,最中间成员的取值好多好多 我中位数。完后 群体总数为偶数,那末 中位数好多好多 我中间有一一一还还有一个多多 成员取值的平均值。按照大于还是小于中位数的标准,成员可不都能否 划分为数目相同的两组。对这两组再求中位数,就可不都能否 获得下四分位数(lower quartile)和上四分位数(upper quartile)。[$Q_1$]和[$Q_3$]之间的距离,称为四分位距(IQR,inter quartile range),也是有一一一还还有一个多多 常见的群体参数。亲戚亲戚亲戚朋友用下面符号表示:

$$Q_1 = lower\ quartile$$

$$Q_2 = M = median$$

$$Q_3 = upper\ quartile$$

$$IQR = Q_3 - Q_1$$

中位数是按照80%划分数据,下四分位数是按照25%划分数据,上四分位数是按照75%划分数据。觉得,中位数和四分位数都属于百分位数(percentile)。亲戚亲戚亲戚朋友用任意比例来划分数据,从而取得百分位数。把数据按数值大小排列,发生p%位置的成员的取值,称第p百分位数

mean: 172.075924
variance: 102.570849846
standard deviation: 10.1277267857
median: 172.21
lower percentile: 165.31
upper percentile: 178.9025
IQR: 13.5925

代码如下:

import numpy as np

with open("xiangbei_height.txt", "r") as f:
        lines = f.readlines()

x = list(map(float, lines))
print("mean:", np.mean(x))
print("variance:", np.var(x))
print("standard deviation:", np.std(x))
print("median:", np.median(x))
print("lower percentile:", np.percentile(x, 25))
print("upper percentile:", np.percentile(x, 75))
print("IQR:", np.percentile(x, 75) - np.percentile(x, 25))

数据绘图

数据绘图利用了人类对形态的敏感。在通过数据绘图,亲戚亲戚亲戚朋友可不都能否 将数字转换的几何图形,让数据中的信息变得更容易消化。数据绘图完后 是个费时费力的手工活,但计算机图形的发展让数据绘图变得简单。这两年更是新兴起“数据可视化”,用好多好多 炫目的手段来呈现数据。但说到底,经典的绘图那末 那末 几种,如饼图、散点图、曲线图。“数据可视化”中的创新手法,也只不过是从哪些地方地方经典依据中衍生出来的。完后 亲戚亲戚亲戚朋友完后 形成了约定俗成的数据绘图习惯,绘图依据上的过度创新甚至会误导读者。好多好多 ,这里冒出的,也是经典的统计绘图形式。

完后 这些系列统计教程主要用Python,我将基于Matplotlib介绍几种经典的数据绘图依据。Matplotlib是基于numpy的一套Python工具包,提供了雄厚的数据绘图工具。当然,Matplotlib不须唯一的选泽。有的统计学家更偏爱R语言,而Web开发者流行使用D3.js。熟悉了这些 绘图工具后,总可不都能否 触类旁通,越快地掌握一些的工具。

饼图

亲戚亲戚亲戚朋友将以2011年几块国家的GDP数据为例子,看看怎么绘制经典的饼图和条形图。数据如下:

USA        8094025
China      11299967
India       4457784
Japan       4440376
Germany     8099080
Russia      2383402
Brazil      2293954
UK          2280803
France      2217900
Italy       1846980                                                                                                                                                                                                                                 

这是有一一一还还有一个多多 那末 10个成员的群体。群体成员的取值即该成员的2011年的GDP总额。这里的单位是(百万美元)。

亲戚亲戚亲戚朋友先来绘制饼图 (pie plot)。绘制饼图就像分披萨。整个披萨代表成员取值的总和。每个成员根据此人 取值的大小,拿相应大小的那块儿披萨。把中间的数据绘制成饼图:

从图中可不都能否 看后,在这场“分大饼”的游戏中,美国和中国占了大的份额。不过,亲戚亲戚亲戚朋友从饼图中读到的好多好多 我比例,没依据获得成员的具体数值。而且,饼图适用于表示成员取值在总和中所占的百分比。中间饼图的代码如下:

import matplotlib.pyplot as plt


# quants: GDP
# labels: country name
labels   = []
quants   = []

# Read data
with open('major_country_gdp.txt', 'r') as f:
    for line in f:
        info = line.split()
        labels.append(info[0])
        quants.append(float(info[1]))

print(quants)
# make a square figure
plt.figure(1, figsize=(6,6))

# For China, make the piece explode a bit
def explode(label, target='China'):
    if label == target:
        return 0.1
    else:
        return 0
expl = list(map(explode,labels))

# Colors used. Recycle if not enough.
colors  = ["pink","coral","yellow","orange"]

# Pie Plot
# autopct: format of "percent" string;
plt.pie(quants,
        explode=expl, colors=colors, labels=labels,
        autopct='%1.1f%%',pctdistance=0.8, shadow=True)
plt.title('Top 10 GDP Countries (2011)', bbox={'facecolor':'0.8', 'pad':5})

plt.show()

条形图和直方图

饼图的缺点是无法表达成员的具体取值,而条形图(bar plot)正是用于呈现数据取值。条形图绘制的是有一一一还还有一个多多 个竖直的长条,这些长条的高度就代表了取值。还是用中间2011年GDP的数据,用条形图绘制出来好多好多 我:

条形图有水平和竖直有一一一还还有一个多多 方向。水平方向上标出了每个竖条对应的国家,竖直方向标出了GDP的数值。完后 ,读者就可不都能否 读出每个国家的GDP了。中间绘图的代码如下:

import matplotlib.pyplot as plt
import numpy as np


# quants: GDP
# labels: country name
labels   = []
quants   = []

# Read data
with open('major_country_gdp.txt') as f:
    for line in f:
        info = line.split()
        labels.append(info[0])
        quants.append(float(info[1]))

width = 0.4
ind = np.linspace(0.5,9.5,10)
# make a square figure
fig = plt.figure(1, figsize=(12,6))
ax  = fig.add_subplot(111)

# Bar Plot
ax.bar(ind-width/2,quants,width,color='coral')

# Set the ticks on x-axis
ax.set_xticks(ind)
ax.set_xticklabels(labels)
# labels
ax.set_xlabel('Country')
ax.set_ylabel('GDP (Million US dollar)')
# title
ax.set_title('Top 10 GDP Countries (2011)', bbox={'facecolor':'0.8', 'pad':5})
plt.show()

基本的条形图好多好多 我完后 这些 标记数据取值的绘图依据。完后 想知道数值,那末 可不都能否 直接从数据表中读出来,大可不都能否 不须画条形图。统计绘图中更常用这些 从条形图中衍生出来的绘图依据:直方图(histogram)。直方图会对群体数据进行预防止,而且再把预防止结果用条形图的形式画出来。举有一一一还还有一个多多 简单的例子,在绘图中呈现湘北高中所有学生的身高数据。想象一下,完后 让每个学生的身高对应有一一一还还有一个多多 竖条,那末 图上就会密密麻麻地挤满数千个竖条,不难 提供有价值的信息。但完后 画成直方图的形式,看起来就会如下图:

在这幅图中,横坐标成了身高取值。每个竖条的高度对应了一定的身高范围,类式170cm到172cm。竖条的高度,对应了身高在该区间内的学生数。而且,直方图先进行了一次分组的预防止,而且用条形图的依据,画出了每个组中蕴含的成员总数。在分组的防止中,一些原始信息丢失,以至于从竖条中没依据读出学生的具体身高。但得到比较复杂的信息变得更容易理解。看后这些图完后 ,亲戚亲戚亲戚朋友可不都能否 有信心地说,大每段学生的身高在170cm周边。而身高低于80cm完后 身高高于190cm的学生发生的比例很少。完后 有一一一还还有一个多多 人好多好多 我读原始数据,不难 短时间内获得中间的结论。

直方图绘图系统进程如下:

import numpy as np
import matplotlib.pyplot as plt

with open("xiangbei_height.txt", "r") as f:
    lines = f.readlines()

x = list(map(float, lines))

plt.title("Heights of Students (Shohoku High School)")
plt.hist(x, 80)
plt.xlabel("height (cm)")
plt.ylabel("count")
plt.show()

代码中的hist()函数用于绘制直方图,其中的80说明了要生成的区间分组的个数。根据须要,你也可不都能否 具体说明在哪些地方区间形成分组。

趋势图

趋势图(run chart)又称为折线图,一个劲用于呈现时间序列。时间序列是随着时间产生的一组数据,比如上海去年每一天的气温,再比如中国最近80年的GDP。趋势图会把相邻时间点的数据用直线连接起来,从而从视觉上体现出数据随时间变化的形态。趋势图在生活中很常见,类式股民就一个劲会通过类式的图来了解股价随时间的变化。下面是中国1980-2015年GDP的趋势图:

在这些趋势图中很容易看后,中国的GDP随着时间快速增长。绘图的代码如下:

import numpy as np
import matplotlib.pyplot as plt


# read data
with open("China_GDP.csv", "r") as f:
    lines = f.readlines()
    info = lines[1].split(",")

# convert data
x = []
y = []

def convert(info_item):
    return float(info_item.strip('"'))

for count, info_item in enumerate(info):
    try:
        y.append(convert(info_item))
        x.append(1980 + count)
    except ValueError:
        print("%s is not a float" % info_item)

# plot
plt.title("China GDP")
plt.plot(x, y)
plt.xlabel("year")
plt.ylabel("GDP (USD)")
plt.show()

散点图

中间的绘图依据,本质上全部后会二维统计图。饼图是国别和比例的二维信息,直方图体现了身高和人数的二维关系,趋势图的有一一一还还有一个多多 维度则是时间和GDP。散点图(scatter plot)是这些 最直接的表达二维关系的绘图依据。二维绘图的一些依据,都可不都能否 理解成散点图的有一一一还还有一个多多 变种。

散点图通过在二维平面上标记出数据点来呈现数据。完后 亲戚亲戚亲戚朋友想研究湘北高中学生身高和体重的关系,就可不都能否 在表示“身高-体重”的二维平面上,标记出所有成员的数据:

在这些散点图中,二维平面的横向代表身高,纵向代表体重,每有一一一还还有一个多多 点代表了有一一一还还有一个多多 学生。通过这些点对应的横纵坐标,就可不都能否 读出该学生的身高和体重。散点图可不都能否 直观地呈现所有数据,而且上可不都能否 别问亲戚亲戚亲戚朋友整体分布上有何形态。亲戚亲戚亲戚朋友从图中可不都能否 看后,体重大体上随着身高增长而增长。

绘图代码如下:

import numpy as np
import matplotlib.pyplot as plt


def read_data(filename):
    with open(filename) as f:
        lines = f.readlines()
    return np.array(list(map(float, lines)))

height = read_data("xiangbei_height.txt")
weight = read_data("xiangbei_weight.txt")

plt.scatter(height, weight)

plt.title("Shohoku High School")
plt.xlabel("height(cm)")
plt.ylabel("weight(kg)")
plt.ylim([20, 120])

plt.show()

散点是通过二维的位置来表示数据。在应用中,还可不都能否 通过散点的大小来表示三维的数据。这些进化了的散点图称为泡泡图(bubble plot)。除了散点的大小,泡泡图有时后会用散点的颜色来表达更高维度的信息。

亲戚亲戚亲戚朋友来看泡泡图的有一一一还还有一个多多 例子。下图中绘出了亚洲主要城市的人口。城市的位置蕴含了二维的信息,即经度和纬度。此外,人口构成了第三维。亲戚亲戚亲戚朋友用散点的大小来表示这些维度。

 

数据如下:

Shanghai 28019148  31.23N  121.47E  China
Mumbai   12478447  18.96N  72.82E   India
Karachi  18080000  24.86N  67.01E   Pakistan
Delhi    16314838  28.67N  77.21E   India
Manila   11855975  14.62N  120.97E  Philippines
Seoul    23618000  37.56N  126.99E  Korea(South)
Jakarta  28019545   6.18S  106.83E  Indonesia
Tokyo    35682480  35.67N  139.77E  Japan
Peking   19612368  39.91N  116.39E  China

代码中使用了matplotlib的Basemap模块来绘制地图:

from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np

#============================================# read data
names = []
pops  = []
lats  = []
lons  = []
countries = []

with open("major_city.txt", "r") as f:
    for line in f:
        info = line.split()
        names.append(info[0])
        pops.append(float(info[1]))
        lat  = float(info[2][:-1])
        if info[2][-1] == 'S': lat = -lat
        lats.append(lat)
        lon  = float(info[3][:-1])
        if info[3][-1] == 'W': lon = -lon + 380.0
        lons.append(lon)
        country = info[4]
        countries.append(country)

#============================================
# set up map projection with
# use low resolution coastlines.
map = Basemap(projection='ortho',lat_0=35,lon_0=120,resolution='l')

# draw coastlines, country boundaries, fill continents.
map.drawcoastlines(linewidth=0.25)
map.drawcountries(linewidth=0.25)

# draw the edge of the map projection region (the projection limb)
map.drawmapboundary(fill_color='#689CD2')

# draw lat/lon grid lines every 80 degrees.
map.drawmeridians(np.arange(0,380,80))
map.drawparallels(np.arange(-90,90,80))

# Fill continent wit a different color
map.fillcontinents(color='#BF9E80',lake_color='#689CD2',zorder=0)

# compute native map projection coordinates of lat/lon grid.
x, y = map(lons, lats)
max_pop = max(pops)

# Plot each city in a loop.
# Set some parameters
size_factor = 180.0
y_offset    = 15.0
rotation    = 80

adjust_size = lambda k: size_factor*(k-8000000)/max_pop
for i,j,k,name in zip(x,y,pops,names):
    cs = map.scatter(i,j,s=adjust_size(k),marker='o',color='#FF5800')
    plt.text(i,j+y_offset,name,rotation=rotation,fontsize=10)
    print(i, j)
examples = [1800000, 2800000, 38000000]

pop = 1800000
plt.scatter(80000, 80000,s=adjust_size(pop),marker='o',color='red')
plt.text(80000, 80000+y_offset,str(pop/800000) + "million",rotation=0,fontsize=10)

pop = 2800000
plt.scatter(380000, 80000,s=adjust_size(pop),marker='o',color='red')
plt.text(380000, 80000+y_offset,str(pop/800000) + "million",rotation=0,fontsize=10)

pop = 38000000
plt.scatter(680000, 80000,s=adjust_size(pop),marker='o',color='red')
plt.text(680000, 80000+y_offset,str(pop/800000) + "million",rotation=0,fontsize=10)


plt.title('Major Cities in Asia & Population')
plt.show()

箱形图

完后 的绘图依据侧重点在原始数据。还有一些绘图是为了呈现群体参数,比如箱形图(box plot)。比如湘北高中身高数据绘制成箱形图:

 

如图中标注的,箱形图体现的主好多好多 我中位数和四分位数。上下四分位数构成了箱子,其中蕴含了一半的数据成员。此外,上下还有有一一一还还有一个多多 边界,发生箱子的上下边缘各外推1.八个箱子高度的位置。完后 外推1.八个箱子位置超出了数据库的极值,那末 边界再加极值的高度。而且,将有数据点超出边界。哪些地方地方数据点被认为是异常值(outlier),用散点的依据画出。

代码如下:

import matplotlib.pyplot as plt


with open("xiangbei_height.txt", "r") as f:
        lines = f.readlines()

x = list(map(float, lines))
plt.boxplot(x)

plt.title("box plot of Shohoku High School")
plt.xticks([1], ['Shohoku'])
plt.ylabel("height (cm)")
plt.show()

箱形图体现了有一一一还还有一个多多 思路,好多好多 我在绘制原始数据的并肩画出群体参数,从而辅助亲戚亲戚亲戚朋友理解数据。比如,亲戚亲戚亲戚朋友可不都能否 在直方图中标出平均值和标准差:

代码如下:

import numpy as np
import matplotlib.pyplot as plt

with open("xiangbei_height.txt", "r") as f:
    lines = f.readlines()

x = list(map(float, lines))

plt.title("Heights of Students (Shohoku High School)")

plt.hist(x, 80)
plt.xlabel("height (cm)")
plt.ylabel("count")

mu  = np.mean(x)
std = np.std(x)

h = 120
text_color = "white"

plt.axvline(x=mu, color="red")
plt.text(mu, h,'mean',rotation=90,color=text_color)

plt.axvline(x=mu-std, color="coral")
plt.text(mu-std, h,'mean-std',rotation=90,color=text_color)

plt.axvline(x=mu+std, color="coral")
plt.text(mu+std, h,'mean+std',rotation=90,color=text_color)

plt.show()

怎么画好图

尽管这里说明了一些常用的数据绘图依据,但数据绘图的过程蕴含好多好多 人为创作的因素在。而且,同有一一一还还有一个多多 数据库,甚至同这些 绘图形式,都完后 产生多种多样的数据图像。不同的数据图像,在传递信息的有效性上,会产生不小的差别。怎么画好数据图呢?我根据此人 的经验,总结了下面几块标准:

  1. 选泽目的。尽管在研究过程中,亲戚亲戚亲戚朋友会画出大量的数据图,但在展示数据图时,要有所侧重。
  2. 在标题中说明一张数据图的主要内容。
  3. 标明每有一一一还还有一个多多 坐标轴,并标明坐标的刻度和单位。
  4. 完后 那末 坐标轴,须要用图例来说明读数。类式在泡泡图中用图例说明泡泡大小所代表的读数。
  5. 在图中标注附加的图像元素,如代表平均值的标示线、代表拟合的虚线曲线等。
  6. 备份数据、图像文件和相关代码。

在介绍一副数据图时,也可不都能否 遵循一定的顺序:

  1. 语录说明画了哪些地方:“这幅图描绘了湘北高中学生身高分布。”
  2. 说明坐标轴:“图中横轴代表了身高,纵轴代表了人数。”
  3. 说明主要图像元素的含义:“每个竖条对应一定的身高区间。竖条的高度,代表了该身高区间内学生的人数。”
  4. 说明每段图像元素的含义:“红线代表了学生的平均身高。”
  5. 引导读者深入解读:“可不都能否 看后,学生身高大多集中在平均值周边……”

当然,对于发生人为创作因素的数据绘图来说,也那末 定法。但建立一定的流程,能提高绘图的速率单位。好多好多 我也建议你建立此人 的绘图流程。

总结

在这些篇文章里,我主要用参数和绘图呈现群体的数据。类式的依据还一个劲用于呈现样品数据。完后 在描绘样品时须要涉及到统计推断,好多好多 我把样品描绘的依据插进将在统计推断的相关文章中讲解。

完后 你想更多地了解Matplotlib,可不都能否 参考官方文档,以及我完后 写的这篇文章:matplotlib核心剖析 。

欢迎继续阅读“数据科学”系列文章