1. pandas 绘图函数
pandas有许多能够利用DataFrame对象数据组织特点来创建标准图表的高级绘图方法
线型图:
Series和DataFrmae都有一个用于生成各类图表的plot方烤鸡。默认情况下,它们所生成的是线型图。
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt
(1)Series的plot
s=Series(np.random.randn(10).cumsum(),index=np.arange(0,100,10))
s.plot()
plt.show()
#Series对象的索引会被传给matplotlib,并用以绘制X轴。可以通过user_index=False禁用该功能
#X轴的刻度和界限可以通过xticks和xlim选项进行调节,Y轴就用yticks和ylim.
(2)DataFrame的plot
#pandas的大部分绘图方法都有一个可选的ax参数,它可以是一个matplotlib的subplot对象。这使你能够
#在网格布局中更为灵活地处理subplot的位置。
#DataFrame的plot方法会在一个subplot中为各列绘制一条线,并自动创建图例
df=DataFrame(np.random.randn(10,4).cumsum(0),
columns=['A','B','C','D'],
index=np.arange(0,100,10))
df.plot()
plt.show()
Series.plot方法的参数:
参数 说明
label 用于图例的标签
ax 要在其上进行绘制的matplotlib subplot对象。如果没有设置,则使用当前matplotlib subplot对象。
如果没有设置,则使用当前matplotlib subplot对象。
style 将要传给matplotlib的风格字符串(如‘ko--’)
alpha 图表的填充不透明度(0到1之间)
kind 可以是line,bar,barh,kde
logy 在Y轴上使用对数标尺
use_index 将对象的索引用作刻度标签
rot 旋转刻度标签(0 到 360)
xticks 用作X轴刻度的值
yticks 用作Y轴刻度的值
xlim X轴的界限(例如[0,10])
ylim Y轴的界限
grid 显示轴网格线(默认打开)
DataFrame.plot方法的参数:
参数 说明
subplots 将各个DataFrame列绘制到单独的subplot中
sharex 如果subplots=True,则共用同一个X轴,包括刻度和界限
sharey 如果subplots=True,则共用同一个Y轴
figsize 表示图像大小的元组
title 表示图像标题的字符串
legend 添加一个subplot图例(默认为True)
sort_columns 以字母表顺序绘制各列,默认使用当前列顺序
注:matplotlib.pyplot的一些方法可以参照pandas 绘图中matplotlib的那章
柱状图:
只要将kind='bar'(垂直柱状图)或kind='barh'(水平柱状图)即可生成柱状图。这时,Series和DataFrame
的索引将会被用作X(bar)或Y(barh)刻度:
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt
fig,axes=plt.subplots(2,1)
data=Series(np.random.rand(16),index=list('abcdefghijklmnop'))
data.plot(kind='bar',ax=axes[0],color='k',alpha=0.7)
data.plot(kind='barh',ax=axes[1],color='k',alpha=0.7)
plt.show()
(1) Stacked=True即可为DataFrame生成堆积柱状图,这亲每行的值就会被堆积在一块。
(2)value_counts图形化显示Series中各值的出现频率
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt
#DataFrame会按照行对数据进行分组
fig,axes=plt.subplots(1,1) #窗口只有一个子图,并且画在第一个图上
data=DataFrame(np.random.randn(6,4),index=['one','two','three','four','five','six'],
columns=pd.Index(['A','B','C','D'],name='Genus'))
print data
data.plot(kind='bar')
plt.show()
#这里的stacked是标明画累计柱图
data.plot(kind='bar',stacked=True,alpha=0.5)
plt.show()
#Series的value_counts可以用来显示Series中各值的频数
s=Series([1,2,2,3,4,4,4,5,5,5])
s.value_counts().plot(kind='bar')
plt.show()
下面再看一个例子:
#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
#下面是一个例子:做一张堆积柱状图来显示每天各种聚会规模的数据点百分比
tips = pd.read_csv('E:\\tips.csv')
party_counts = pd.crosstab(tips.day,tips.size)
print party_counts
party_counts = party_counts.ix[:,2:5]
#然后进行归一化是各行和为1
party_pcts = party_counts.div(party_counts.sum(1).astype(float),axis = 0)
print party_pcts
party_pcts.plot(kind = 'bar',stacked = True)
plt.show()
直方图和密度图:
#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
#绘制小费百分比直方图
tips = pd.read_csv('E:\\tips.csv')
tips['tip_pct'] = tips['tip'] / tips['total_bill']
#bins规定一共分多少个组
tips['tip_pct'].hist(bins = 50)
plt.show()
#与此相关的是密度图:他是通过计算“可能会产生观测数据的连续概率分布的估计”
#而产生的。一般的过程将该分布金思维一组核(诸如正态之类的较为简单的分布)。
#此时的密度图称为KDE图。kind = ‘kde’即可。
tips['tip_pct'].plot(kind = 'kde')
plt.show()
#显然,直方图和密度图经常会在一起出现
comp1 = np.random.normal(0,1,size = 200)
comp2 = np.random.normal(10,2,size = 200)
values = Series(np.concatenate([comp1,comp2])) #concatenate连接两个数据为一个Series,和concate差不多
print values
values.hist(bins = 100,alpha = 0.3,color = 'k',normed = True)
values.plot(kind = 'kde',style = 'k--')
plt.show()
散布图:
散布图(scantter plot)是观察两个一维数据序列之间的关系的有效手段。matplotlib中的scantter方法是绘制散布图的主要方法。
#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
#下面加载macrodata中的数据集,选择其中几列并计算对数差
macro = pd.read_csv('E:\\macrodata.csv')
data = macro[['cpi','m1','tbilrate','unemp']]
#这里的diff函数是用来计算相邻两数只差,对每一列,后一个数减前一个数
trans_data = np.log(data).diff().dropna()
#print np.log(data).head()
#print np.log(data).diff().head()
print trans_data.head()
plt.scatter(trans_data['m1'],trans_data['unemp'])
plt.title('Changes in log %s vs. log %s'%('m1','unemp'))
plt.show()
在探索式数据分析工作中,同时观察一组变量的散布图是很有意义的,这也被称为散布图矩阵。
#画散布图矩阵式很有意义的pandas提供了scantter_matrix函数来创建散步矩阵
#关于 diagonal 参数,是为了不让对角线上的图形(自己和自己的散布图)显示为一条直线而设置的关于这种数据的某些图形显示
# digonal参数是表示在对角线上放置各变量的直方图或密度图。
#比如 diagonal = 'kde'就是画密度图且核为kde,若diagonal='hist',则为直方图
pd.scatter_matrix(trans_data,diagonal = 'kde',color = 'k',alpha = 0.3)
pd.scatter_matrix(trans_data,diagonal = 'hist',color = 'k',alpha = 0.3)
plt.show()
绘制地图:图形化显示海地地震危机数据
由于Basemap未安装成功,无法显示下面的图形
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt
#(1)先将csv文件的数据加载到DataFrame中
data=pd.read_csv('/Users/mac/PycharmProjects/python2.7/BigData/pydata-book-2nd-edition/datasets/haiti/Haiti.csv')
# print data
#(2)处理一下这些数据,看看哪些是我们想要的。每一行表示一条数据,每条数据都有一个时间戳和位置(经度和纬度)
# print data[['INCIDENT DATE','LATITUDE','LONGITUDE']][:10]
#输出结果如下:
# INCIDENT DATE LATITUDE LONGITUDE
# 0 05/07/2010 17:26 18.233333 -72.533333
# 1 28/06/2010 23:06 50.226029 5.729886
# 2 24/06/2010 16:21 22.278381 114.174287
# 3 20/06/2010 21:59 44.407062 8.933989
# 4 18/05/2010 16:26 18.571084 -72.334671
# 5 26/04/2010 13:14 18.593707 -72.310079
# 6 26/04/2010 14:19 18.482800 -73.638800
# 7 26/04/2010 14:27 18.415000 -73.195000
# 8 15/03/2010 10:58 18.517443 -72.236841
# 9 15/03/2010 11:00 18.547790 -72.410010
#(3)Category字段含有一组以逗号分隔的代码,这些代码表示消息的类型:
# print data['CATEGORY'][:6]
# 输出结果如下:
# 0 1. Urgences | Emergency, 3. Public Health,
# 1 1. Urgences | Emergency, 2. Urgences logistiqu...
# 2 2. Urgences logistiques | Vital Lines, 8. Autr...
# 3 1. Urgences | Emergency,
# 4 1. Urgences | Emergency,
# 5 5e. Communication lines down,
# Name: CATEGORY, dtype: object
#(4)调用describe还能发现数据中存在一些异常的地址位置
# print data.describe()
#输出结果如下:
# Serial LATITUDE LONGITUDE
# count 3593.000000 3593.000000 3593.000000
# mean 2080.277484 18.611495 -72.322680
# std 1171.100360 0.738572 3.650776
# min 4.000000 18.041313 -74.452757
# 25% 1074.000000 18.524070 -72.417500
# 50% 2163.000000 18.539269 -72.335000
# 75% 3088.000000 18.561820 -72.293570
# max 4052.000000 50.226029 114.174287
#(5)消除错误位置信息,并移除缺失分类信息的数据
data=data[(data.LATITUDE > 18) & (data.LATITUDE <20) &
(data.LONGITUDE > -75) & (data.LONGITUDE < -70) &
data.CATEGORY.notnull()]
#(5)现在我们想根据分类对数据做一些分析或图形化工作,但是各个分类字段中可能含有多个分类。
#此外各个分类信息不仅有一个编码,还有一个英文名称(可能还有一个法语名称)。因此需要对
#数据做一些规整化处理。首先,编写两个函数,一个用于获取所有分类的列表,另一个用于
# 将各个分类信息拆分为编码和英语名称
#注意作者的一些隐式循环写法
print '++++++++++++++++++++++++++++++++++++'
def to_cat_list(catstr):
stripped=(x.strip() for x in catstr.split(','))
return [x for x in stripped if x]
def get_all_categories(cat_series):
cat_set=(set(to_cat_list(x)) for x in cat_series) #set集合是无序的
return sorted(set.union(*cat_set)) #cat_set是一个可迭代的数组,故*cat_set
# a="a,b,c"
# print get_all_categories(a)
def get_english(cat):
code,names=cat.split('.')
if '|' in names:
names=names.split('|')[1]
return code,names.strip()
#测试一下get_english函数是否工作正常:
print get_english('4e. Assainissement eau et hygiene | Water sanitation and hygiene')
#输出结果如下:
# ('4e', 'Water sanitation and hygiene')
#(6)接下来,做了一个将编码和名称映射起来的字典,因为我们等会要用编码进行分析。后面我们在修饰图表时也会用到这个
#注意:这里用的是生成器表达式,而不是列表推导式。
# print data.CATEGORY
#生成字典
all_cats=get_all_categories(data.CATEGORY) #获取了category的所有列表
#生成器表达式,
english_mappling=dict(get_english(x) for x in all_cats)
# print english_mappling['2a']
#输出结果:Food Shortage
# print english_mappling['6c']
#输出结果:Earthquake and aftershocks
#(7)根据分类选取记录的方式有很多,其中之一是添加指标列,每个分类一列。为此,我们首先抽取出唯一的分类编码,
#并构造一个全零DataFrame(列为分类编码,索引跟data的索引一样)
def get_code(seq):
return [x.split('.')[0] for x in seq if x]
#下面是将所有的key取出来
all_code=get_code(all_cats)
# print all_code
#输出结果如下:
# ['1', '1a', '1b', '1c', '1d', '2', '2a'】
code_index=pd.Index(np.unique(all_code)) #Index后面DataFrame中的行/列,去重
dummy_frame=DataFrame(np.zeros((len(data),len(code_index))),index=data.index, #行为数据的行索引
columns=code_index) #创建行X列为(len(data),len(code_index))的全零的DataFrame
# print dummy_frame.ix[:,:6] #ix取行索引,全部数据的,前6行
#输出结果如下:
# 1 1a 1b 1c 1d 2
# 0 0.0 0.0 0.0 0.0 0.0 0.0
# 4 0.0 0.0 0.0 0.0 0.0 0.0
# 5 0.0 0.0 0.0 0.0 0.0 0.0
# 6 0.0 0.0 0.0 0.0 0.0 0.0
#(8)现在应该将各行中适当的项设置为1,然后再与data进行连接
for row,cat in zip(data.index,data.CATEGORY):
# print row,cat #输出:3553 8e. Nouvelles de Personnes | Persons News,
codes=get_code(to_cat_list(cat))
dummy_frame.ix[row,codes]=1
# print dummy_frame[:5]
#添加前缀,并且合并一下
data=data.join(dummy_frame.add_prefix('category_')) #category_0,category_1...
print data.ix[:,10:15]
#输出结果如下:
# category_1 category_1a category_1b category_1c category_1d
# 0 1.0 0.0 0.0 0.0 0.0
# 4 1.0 0.0 0.0 0.0 0.0
# 5 0.0 0.0 0.0 0.0 0.0
#(9)接下来开始画图,由于这是空间坐标数据,因此我们希望把数据绘制在海地的地图上。
#使用basemap工具集使得我们能够用python在地图上绘制2D数据。basemap提供了许多没的地球投影
#以及一种将地球上的经纬度坐标投影转换为二维matplotlib图的方式
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
def basic_haiti_map(ax=None,lllat=17.25,urlat=20.25,
lllon=-75,urlon=-71):
#创建极球面投影的Basemap实例
m=Basemap(ax=ax,projection='stere',lon_0=(urlon+lllon)/2,
lat_0=(urlat+lllat)/2,
llcrnrlat=lllat,urcrnrlat=urlat,
llcrnrlon=lllon,urcrnrlon=urlon,
resolution='f')
#绘制海岸线、州界、国界及地图边界
m.drawcoastlinew()
m.drawstates()
m.drawcountries()
return m
#(11)现在问题是:如何让返回的这个Basemap对象知道该怎样将坐标转换到画布上。
#对于每一个分类,我在数据集中找到了对应的坐标,并在适当的subplot中绘制一个Basemap,转换坐标,
#然后通过Basemap的plot方法绘制点:
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(12,10))
print fig,axes
fig.subplots_adjust(hspace=0.05,wspace=0.05)
to_plot=['2a','1','3c','7a']
lllat=17.25
urlat=20.25
lllon=-75
urlon=-71
for code,ax in zip(to_plot,axes.flat):
m=basic_haiti_map(ax,lllat=lllat,urlat=urlat,
lllon=lllon,urlon=urlon)
cat_data=data[data['category_%s' % code]==1]
#计算地图的投影坐标
x,y=m(cat_data.LONGITUDE,cat_data.LATITUDE)
m.plot(x,y,'k.',alpha=0.5)
ax.set_title('%s:%s' % (code,english_mappling[code]))
Chaco
还有一些可以绘制静太图又可以生成交互式图形的绘图工具包有:Chaco,mayavi,pyQwt,Veusz,gnuplot-py,biggles等.
chaco对交互的支持要好得多,而且渲染速度很快,如果要创建交互式的GUI应用程序,它确实是个不错的选择。web式的图形化
是后面的发展方向(如javascript),于是开发方向就变成了实现数据分析和准备工具(如pandas)与web浏览器之间更为紧密的
集成。