pandas is a Python package providing fast, flexible, and expressive data structures designed to make working with “relational” or “labeled” data both easy and intuitive. It aims to be the fundamental high-level building block for doing practical, real world data analysis in Python. Additionally, it has the broader goal of becoming the most powerful and flexible open source data analysis / manipulation tool available in any language. It is already well on its way toward this goal.
NumPy is the fundamental package for scientific computing with Python. It contains among other things:
Matplotlib是一个Python的2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形。 通过Matplotlib,开发者可以仅需要几行代码,便可以生成绘图,直方图,功率谱,条形图,错误图,散点图等。
Seaborn is a library for making attractive and informative statistical graphics in Python. It is built on top of matplotlib and tightly integrated with the PyData stack, including support for numpy and pandas data structures and statistical routines from scipy and statsmodels.
In [6]:
%matplotlib inline
from pandas import Series, DataFrame
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
以上引入各类利用pandas做数据分析可视化的模块,一般可作为每次数据分析项目/任务的起始代码,其中:
%matplotlib inline
是jupyter notebook的一个魔法命令,能够使基于matplotlib的绘图直接显示在网页中from pandas import Series, DataFrame
,从pandas中引入最为常用的两个对象:Series及DataFrame注意,在以上的引入中,类似pd
、np
、plt
及sns
均为约定俗成的习惯性名称,不建议更改。
In [7]:
words_freq = [200,300,400,350,390,600,900,400,300,120]
freq_dict = {'天长地久':words_freq}
total_words_freq = [12345000,23456000,22333000,45632000,11144000,65433000,44444000,55555000,34522000,55566000]
years = [2006,2007,2008,2009,2010,2011,2012,2013,2014,2015]
以上代码中:
words_freq
,是“天长地久”在2006-2015年10年之间的频次listfreq_dict
,键为“天长地久”,值为其历时频次的listtotal_words_freq
,是每年统计文本语料的总字数listyears
,是年份list
In [8]:
s = Series(words_freq)
s
Out[8]:
利用list来初始化Series对象。Series是pandas内置的处理一维数据的数据类型。
In [9]:
s = Series(freq_dict['天长地久'], index = years)
s
Out[9]:
可以在初始化Series对象时,同时指定索引(index)
In [10]:
s.name = '2006-2015'
s.index.name = 'year'
s
Out[10]:
还可以指定Series对象的名称(name),指定其索引(index)的名称(name)
In [11]:
s.plot()
Out[11]:
Series对象可利用pandas内置的plot()直接绘图,默认为折线图。
折线图多用于展示数值型数据,特别是用于展示历时数据。
统计学中,依据计量尺度,一般可将数据分为三种类型:
In [12]:
s.plot(kind='bar')
Out[12]:
plot()函数的参数kind
,可以指定plot()函数所绘制图形的种类,'bar'
为柱状图。也可以采用这种形式:s.plot.bar()
,效果与指定kind参数为bar类似。
柱状图用宽度相同的柱的高度或长短来表示数据多少。
柱状图一般用于展示分类数据,展示不同类别数据的多少(可将以上数据的每个年份理解为不同类别)。
In [13]:
s.plot(kind='barh')
Out[13]:
'barh'为条形图,与柱状图类似。
In [14]:
s.plot('pie',figsize=(6,6))
Out[14]:
'pie'为饼图。 饼图使用圆形及圆内扇形的角度表示数值大小的图形。
一般也用于展示分类数据,用来表示各分类部分数据占全部数据的比例(频率分布)。
In [15]:
s.plot('pie',figsize=(6,6))
Out[15]:
可利用plot()函数的figsize
参数,设定图形的大小(长与宽)
In [16]:
#python实现
def norm_freq(freqs, total_freqs, per = 1):
return [per * freq/total_freq for freq, total_freq in zip(freqs, total_freqs)]
per = 10000000
s_norm = norm_freq(freq_dict['天长地久'], total_words_freq, per = 10000000)
上面的代码用python实现了将每年的频次归一化为每年每一千万字该词汇出现的频次。
In [17]:
s_norm = Series(s_norm, index = years)
s_norm
Out[17]:
利用归一化处理后的结果初始化一个Series对象s_norm。注意,此时value的数据类型自动转换为float。
In [18]:
#pandas的Series运算
s_norm = per * s / total_words_freq
s_norm
Out[18]:
也可以直接利用pandas的序列运算进行归一化。运算结果与python编写代码一直,但是更简洁。
s_norm = per * s / total_words_freq
,其中s
为Series类型,total_words_freq
为list类型,直接相除运算的结果是将s中每个对应的值除以list中每个值。这种向量/矩阵运算是numpy及pandas中非常常见的情况,一般被称为矢量化操作。
In [19]:
s_norm.plot()
s.plot()
Out[19]:
再次绘图,并将两根折线展示在一个图上。
可以看出,归一化前,峰值出现在2012年;归一化后,峰值出现在2010年。
1.2 求平均值
In [20]:
#python实现
freq_mean = sum(freq_dict['天长地久'])/len(freq_dict['天长地久'])
freq_mean
Out[20]:
计算均值的python代码。
除非特别指出,一般平均值指的就是算数平均值。
In [21]:
#pandas内置求均值函数
s.mean()
Out[21]:
利用内置均值函数mean()更为简洁。
In [22]:
s_mean = Series([freq_mean]*10, index = years)
s_mean
Out[22]:
声明一个每年数值均为均值的Series对象s_mean。
In [23]:
s.plot()
s_mean.plot()
Out[23]:
将频次均值与各年频次画在一个图中
1.3 样本方差、标准差、标准分及变异系数
方差(variance)是在概率论和统计方差衡量随机变量或一组数据时离散程度的度量。
总体:包含所研究的全部个体(数据)的集合。
样本:从总体中抽取的一部分元素的集合。
样本容量:构成样本的元素的数量称为样本容量(size)。
样本方差计算公式为: $$s^2 = \frac{1}{n-1}\sum_{i=1}^{n}(x_i-\widetilde x)^2$$
注意样本方差的公式中,分母为n-1
。
In [24]:
#python实现方差
def variance(freqs):
mean = sum(freqs)/len(freqs)
return sum([(freq-mean)**2 for freq in freqs])/(len(freqs)-1)
freq_var = variance(freq_dict['天长地久'])
freq_var
Out[24]:
上述代码用python实现了求样本方差。
In [25]:
#pandas内置方差
s.var()
Out[25]:
而pandas内置求方差的函数var()更为简洁。·
标准差:标准差是方差的算术平方根。
In [26]:
#pandas内置标准差
s.std()
Out[26]:
Pandas内置std()函数,可得到序列s的标准差。
标准分:变量值与平均数的差除以标准差后的值,也称为z分数(z score)。
标准分的计算公式为: $$z_i=\frac{x_i-\widetilde x}{s}$$
In [27]:
(s-s.mean())/s.std()
Out[27]:
上述代码可得到s中所有数值的标准分,存放在一个Series对象中。 标准差的经验法则(当一组数据对称分布时):
切比雪夫不等式:对任意分布的一组数据,至少有(1-1/k^2)的数据落在正负k个标准差以内(k>1)。
变异系数(离散系数):一组数据的标准差与该组数据均值之比。公式为: $$v_i=\frac{s}{\widetilde x}$$
该系数是测度离散程度的相对统计量,主要用于比较不同演变数据的离散程度(特别对均值差异较大的数据组)。
In [28]:
#变异系数
s.std()/s.mean()
Out[28]:
变异系数可由标准差/均值直接得到。
1.4 中位数、分位数、轴距与箱型图
中位数(median):中数是按顺序排列的一组数据中居于中间位置的数,即在这组数据中,有一半的数据比他大,有一半的数据比他小。如果观察值有偶数个,通常取最中间的两个数值的平均数作为中位数。
In [29]:
s_norm.median()
Out[29]:
Pandas内置了median()函数,即求中位数函数。
分位数是将总体的全部数据按大小顺序排列后,处于各等分位置的变量值。
In [30]:
s_norm.quantile(0.25)
Out[30]:
In [31]:
s_norm.quantile(0.75)
Out[31]:
Pandas内置的quantile()函数可以求任意分位数,参数为0.25即Q1,参数为0.75即Q3。
In [32]:
s_norm.plot(kind='box')
Out[32]:
参数kind为box
时,对应的就是箱型图。
箱型图中间的箱型一般由三根线组成,由下至上分别对应Q1,Q2,Q3;而箱型以外的上下两根线,分别对应最大值与最小值(不含离群点)
箱型图一般用于展示数值型数据,有助于对数据的整体分布有只管了解,特别有利于对离群点/异常点的观察。
In [33]:
#Series箱型图离群点/异常点显示,利用seaborn
sns.boxplot(s_norm)
Out[33]:
由于pandas内置的箱型图默认不含离群点,可直接利用seaborn中的boxplot函数,为Series对象绘制带离群点的箱型图。
1.5 样本的累积和(累积频数与累积频率)
累积频数(cumulative frequencies),将各有序类别或组的频数逐级累加起来的频数。
累积频率(cumulative percentages),将各有序类别或组的百分比逐级累加起来。
In [34]:
s.cumsum()
Out[34]:
Pandas内置了cumsum()函数,可以直接得到累积频数。
In [35]:
s.cumsum().plot()
Out[35]:
利用cumsum()得到的仍然是Series对象,可以直接绘图。
In [36]:
s_ratio = s/s.sum()
s_ratio.cumsum().plot()
Out[36]:
累积频率(累积百分比)可以类似的得到。
sum()
为内置的求Series对象中value和的函数。
1.6 最大值、最小值、众数及总体描述
In [37]:
s.max()
Out[37]:
内置最大值函数max()
In [38]:
s.min()
Out[38]:
内置最小值函数min()
In [39]:
s.mode()
Out[39]:
众数(mode):一组数据中出现次数最多的数据值。一般用于测度分类数据的集中趋势,在数据量较大的时候有意义。 Pandas内置mode()函数,可以直接得到众数,注意众数可能不唯一,如此时s的众数有两个。
In [40]:
s.describe()
Out[40]:
Pandas的descibe()函数,可以给出汇总与描述统计的常用值。其中count为数据个数。
1.7 随机数、直方图、峰度与偏度(公式以后有时间补充)
In [41]:
np.random.seed(66)
调用np中random模块的seed()方法,生成一个随机数种子,在这个种子下,每次第一次生成的随机数均相同。
In [42]:
arr1 = np.random.randn(10000)
arr1
Out[42]:
利用random的randn()函数,生成一个numpy的array类型的对象,大小为10000,可理解为长度为10000的数组(所有数据元素类型相同)。
数组内数据分布为正态分布。randn即random normal。
In [43]:
arr2 = np.random.randn(50)
arr2
Out[43]:
与前类似,生成了一个长度为50的array,数据为正态分布。
In [44]:
s_1 = Series(arr1)
s_2 = Series(arr2)
Numpy的array类型可以直接初始化为Series类型的对象。
In [45]:
s_1.plot(kind='hist')
Out[45]:
直方图(histogram):又称质量分布图,是数值数据分布的精确图形表示。
当plot()函数的kind参数为hist时,即代表直方图。
此外,Pandas内置hist()函数,可对Series对象直接绘制直方图:s_norm.hist()
。
In [46]:
s_1.plot(kind='hist',bins=50)
Out[46]:
Plot()函数有一个重要参数bins
,指定了间隔个数。此处将间隔数设为50.
In [47]:
s_1.plot(kind='kde')
Out[47]:
核密度估计图(Kernel Density Estimation, KDE):采用平滑的峰值函数(“核函数”)来拟合观察到的数据点,从而对真实的概率分布曲线进行模拟。 Pandas的plot()函数中,参数kind的值为kde时,即可绘制KDE图。
In [48]:
sns.distplot(s_1)
Out[48]:
Seaborn中内置的distplot()函数,可以直接对Series对象绘制直方图及KDE图的合一图。
In [49]:
sns.distplot(s_2)
Out[49]:
类似地,可以为s_2绘制histogram及kde图。
In [50]:
s_1.skew(),s_2.skew(),s_1.kurt(),s_2.kurt(),
Out[50]:
偏度(Skewness)、偏态、偏态系数,是统计数据分布偏斜方向和程度的度量,是统计数据分布非对称程度的数字特征。正态分布的偏度为零。
峰度(Kurtosis)、峰态、峰态系数,是描述总体中所有取值分布形态陡缓程度的统计量。正态分布的峰度为3(也有很多将计算得到的峰度-3,而使正态分布峰度为零的做法)。
本例中,s_1比s_2更接近于正态分布。
3.1.1 利用list创建Series
In [51]:
s = Series([x*x for x in range(100)])
s
Out[51]:
In [52]:
s.head()
Out[52]:
数据太长,可用head()函数查看前几个数据。
In [53]:
s.tail(10)
Out[53]:
也可用tail()函数查看最后几个数据,head()及tail()函数内可放整型参数,代表列出的数据个数。
In [54]:
s.values
Out[54]:
查看序列s的值
In [55]:
type(s.values)
Out[55]:
In [56]:
s.index
Out[56]:
In [57]:
type(s.index)
Out[57]:
In [58]:
s2 = Series([x*x for x in range(26)], index=set('abcdefghijklmnopqrstuvwxyz'))
s2.head()
Out[58]:
In [59]:
type(s2.index), s2.index
Out[59]:
3.1.2 利用dict创建Series
In [60]:
data = {'喜欢':3000,'爱':7000,'讨厌':1000,'恨':500}
s3 = Series(data)
s3
Out[60]:
In [61]:
s3 = Series(data, index = ['a','b','c','爱'])
s3
Out[61]:
3.1.3 利用标量创建Series对象
In [62]:
s0 = Series(5, index = ['a','b','c','d','e'])
s0
Out[62]:
3.1.4 利用Series对象创建Series对象
In [63]:
s4 = Series(s3)
s4
Out[63]:
In [64]:
s5 = Series(s4, index = ['喜欢','爱','讨厌','中'])
s5
Out[64]:
3.2 访问Series对象的元素
In [65]:
s4[0], s4['爱'], s4.爱
Out[65]:
In [103]:
s4[0:2]
Out[103]:
In [67]:
s4['喜欢':'爱']
Out[67]:
In [105]:
s4.iloc[1], s4.iloc[1:3]
Out[105]:
In [69]:
s4.index
Out[69]:
In [70]:
s4.values
Out[70]:
In [71]:
for k, v in s4.items():
print(k, v)
In [72]:
for k in s4.keys():
print(k)
In [73]:
for v in s4:
print(v)
In [74]:
for k in s4.index:
print(k)
In [75]:
for v in s4.values:
print(v)
3.3 修改、删除、排序等基本运算
In [76]:
s4[0] = 10000
s4
Out[76]:
In [77]:
s4['爱'] = 4078
s4
Out[77]:
In [78]:
s4[0:3] = 666
s4
Out[78]:
In [79]:
s4.index = ['a', 'b', 'c', 'd']
s4
Out[79]:
In [80]:
s4 = s3.reindex(['喜欢','爱','讨厌','中', 'e'])
s4
Out[80]:
In [81]:
s5 = s4.drop('e')
s4
Out[81]:
In [82]:
s5
Out[82]:
In [83]:
s4+s5
Out[83]:
In [84]:
s4-s5
Out[84]:
In [85]:
s4*s5
Out[85]:
In [86]:
s4/s5
Out[86]:
In [87]:
s4.sort_values()
Out[87]:
In [88]:
s4.sort_index()
Out[88]:
In [89]:
s4.sort_values(ascending=False)
Out[89]:
3.4 处理NaN值
In [90]:
s5 = s4.fillna(1)
s5
Out[90]:
In [91]:
s6 = s4.reindex(['喜欢','爱','不讨厌','中'], fill_value = 0)
s6
Out[91]:
In [92]:
s4.add(s6)
Out[92]:
In [93]:
s4.add(s6, fill_value=0)
Out[93]:
3.5 过滤
In [94]:
s > 1000
Out[94]:
In [95]:
s[s>1000]
Out[95]:
3.6 时间序列(Time Series)示例
In [96]:
rng = pd.date_range('1/1/2012', periods=100, freq='S')
rng
Out[96]:
In [97]:
ts = Series(np.random.randint(0, 500, len(rng)), index=rng)
ts.head()
Out[97]:
In [98]:
ts.plot()
Out[98]:
In [99]:
ts1 = ts.resample('Min').mean()
ts1
Out[99]:
3.7 输出
In [100]:
s.plot()
plt.savefig('test.jpg')
In [101]:
s.to_csv('test.csv')