reading Foundations for Analysis with Python Day 12
《Python数据分析基础》的第九章是书中的最后一章,书中先是回顾了之前学过的内容,前面11篇系列笔记也按照本书的整体框架讲述了很多内容,因为考虑到实际应用和我个人的偏向,省略了一些内容也增加了一些例子。回顾一下,前面我们从Python基础的数据类型和容器开始,讲述了文本文件、csv格式以及Excel格式文件的读写以及数据读入后的分析,还有数据库的读取以及增删改查操作,通过比较具体的商业场景写了较长的代码,还有细致地进行了数据可视化以及脚本运行的自动化。
这篇文章要介绍几个数据分析中还会经常用到的库和内置函数,因为篇幅,没有太深入,因为这章讲到的每一个库都能写好几篇文章了,numpy还有一些专门的厚厚的书,还有介绍了几种常用的数据结构并给出部分代码实现,这几种数据结构是《算法与数据结构》课程的核心内容。
目录
- numpy
- SciPy
- Scikit-Learn
- 栈
- 队列
- 图与树
Python能够应用广泛,其第三方模块功不可没,有着良好的生态,Python的第三方库可以从PyPi获取,一般我们可以通过命令行下用pip安装,Anaconda环境下可以通过conda安装。
numpy
前面我们也有用到numpy,pandas就是基于numpy开发的。
NumPy(读作“Num Pie”)是一个基础 Python 扩展包,它(主要)为数值型数据提供了一个快速高效的多维数据容器 ndarray。它还提供了向量化版本的数学和统计函数,使你可以不使用 for 循环来操作数组。NumPy 提供的强大功能可以对结构化数据(特别是数值型数据)进行读取、重塑、聚合、切片和切块。
numpy中核心的数据容器是数组ndarray,它对数值型数据的处理很高效。
使用例子:
import numpy as np #引入numpy库
nlst1=np.array([1,2,3,4,5,6,7]) #将列表变成ndarray
#如果一个csv文件没有标题行,且数据是由空格隔开的浮点数(这类文件挺普遍的),可通过loadtxt将数据加载到ndarray中
nlst2=np.loadtxt('input_file.csv')
#对于Excel文件,可通过pandas的read_excel 辅助,读入dataframe里再转为numpy数组
#(当然实际数据分析中,我们用dataframe比ndarray更普遍)
import pandas as pd
myDataFrame = pd.read_excel('myExcelInputFile.xlsx')
data = np.array(myDataFrame)
#numpy数组的保存可通过savetxt进行保存
np.savetxt('output_file.txt',nlst2)
#savetxt 默认使用科学计数形式保存数据。如果不想这样,可使用 fmt参数来设置保存数据的形式。
#还可以使用 delimiter 参数来设置列分隔符
np.savetxt('output_file2.csv', nlst2, fmt='%.2f', delimiter=',')
numpy数组的连接
NumPy 使用 concatenate、vstack、r_、hstack 和 c_ 函数来简化多个数组的连接过程。concatenate 函数比其他函数更常用,它使用一个附加参数 axis 将一组数组连接起来,axis 表示数组应该垂直连接(axis=0)还是水平连接(axis=1) 。vstack 函数和 r_ 函数专门用来垂直连接数组,hstack 函数和 c_ 函数专门用来水平连接数组。
import numpy as np
arr_c_v= np.concatenate([array1, array2], axis=0) #垂直连接
arr_c_h=np.concatenate([array1, array2], axis=1) #水平连接
array_v = np.r_[array1, array2] #垂直连接
array_h = np.c_[array1, array2] #水平连接
需要深入了解numpy可以看官方文档。
SciPy
SciPy是另一个 Python 基础扩展包,它提供用于科学计算与统计分析的各种分布和函数,以及数学、科研和工程方面的检验。SciPy 具有广泛的适用范围,它的功能分布在各种子扩展包内。SciPy 的子扩展包提供了非常丰富的操作和计算功能。例如,linalg 扩展包提供了在二维数组上进行快速线性代数运算的功能;interpolate 扩展包提供了在两点之间进行线性插值和曲线插值的功能;stats 扩展包提供了使用随机变量、计算并检验描述性统计量和回归分析的功能。
最小二乘回归
SciPy 提供了 linalg.lstsq 函数来计算线性最小二乘问题的解向量。在计量经济学中会经常见到使用矩阵表示的最小二乘估计模型,**y = Xb + e ** 这里的 y 是一个表示因变量的向量,X 是自变量的系数矩阵,b 是要进行估计的解向量,e 是从数据中计算出的残差向量。
import numpy as np
from scipy import linalg
c1, c2 = 6.0, 3.0
i = np.r_[1:21]
xi = 0.1*i
yi = c1*np.exp(-xi) + c2*xi # c1、c2、i 和 xi用来构造yi
zi = yi + 0.05 * np.max(yi) * np.random.randn(len(yi))
A = np.c_[np.exp(-xi)[:, np.newaxis], xi[:, np.newaxis]]
c, resid, rank, sigma = linalg.lstsq(A, zi) #核心拟合过程包装为一句代码
print(c) #得到的最小二乘问题的解向量
# 输出:
# array([ 5.92380523, 3.08359669])
stats
stats 扩展包提供的功能包括按照特定的分布求值、计算描述性统计量、统计检验、回归分析等。这个扩展包提供了超过 80 个连续随机变量和 10 个离散随机变量。它既可进行单样本分析检验,也可以进行双样本比较检验。扩展包中还有进行核密度估计的函数,或通过一组数据对一个随机变量的概率密度函数进行估计。
from scipy.stats import norm, describe
x = norm.rvs(loc=5, scale=2, size=1000) #从一个均值为5,标准差为2的正态分布中提取出1000个值
print('mean:',x.mean(),end='\t')
print('min:',x.min(),end='\t')
print('max:',x.max(),end='\t')
print('方差:',x.var(),end='\t')
print('标准差:',x.std())
x_nobs, (x_min, x_max), x_mean, x_variance, x_skewness, x_kurtosis = describe(x)
#describe 函数可以返回 x 中的观测数量、最小值和最大值、均值和方差、以及偏斜度和峰度
print(x_nobs)
输出:
Out[12]:
mean: 5.05515355099 min: -1.28331614678 max: 10.8829578383 方差: 4.02020623956 标准差: 2.00504519639
1000
Scikit-Learn
Scikit-Learn 扩展包提供了估计机器学习统计模型的功能,包括回归、分类和聚集模型,还
有数据处理、数据降维和模型选择等功能。Scikit-Learn 既可以处理监督式学习模型,也可
以处理无监督式学习模型,并且Scikit-Learn 内置了很多常用数据集。Python中使用Scikit-Learn拓展包通过语句 import sklearn 引入。
#用SVM(支持向量机)进行手写数字识别
def svmDigitsPic():
from sklearn.datasets import load_digits
from sklearn.cross_validation import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
from sklearn.metrics import classification_report
#以上引入数据集合 svm分类器
digits=load_digits()
print(digits.data.shape) #输出数据集的信息
x_tr,x_tt,y_tr,y_tt=train_test_split(digits.data,digits.target,test_size=0.25,random_state=33)
#用sklearn内置的方法划分训练集和验证集
ss=StandardScaler()
x_tr=ss.fit_transform(x_tr)
x_tt=ss.transform(x_tt)
lsvc=LinearSVC() #基于线性假设的SVM分类器
lsvc.fit(x_tr,y_tr)
y_pred=lsvc.predict(x_tt)
print("Accuracy:",lsvc.score(x_tt,y_tt))
#print(classification_report(y_tt,y_pred))
print(classification_report(y_tt,y_pred,target_names=digits.target_names.astype(str)))
svmDigitsPic()
输出:
Accuracy: 0.953333333333
precision recall f1-score support
0 0.92 1.00 0.96 35
1 0.96 0.98 0.97 54
2 0.98 1.00 0.99 44
3 0.93 0.93 0.93 46
4 0.97 1.00 0.99 35
5 0.94 0.94 0.94 48
6 0.96 0.98 0.97 51
7 0.92 1.00 0.96 35
8 0.98 0.84 0.91 58
9 0.95 0.91 0.93 44
avg / total 0.95 0.95 0.95 450
栈
栈最大的特点就是LIFO(last in, first out,后入先出),因此也称为后进先出表。栈是一个项目的有序集合,既可以向栈中的一端添加数据,又可以从同一端删除一个数据,但一次只能添加或删除一个数据。可以添加和删除项目的一端称为栈顶,相反的一端称为栈底。给定了栈顶和栈底之后,栈顶附近的项目停留在栈中的时间要少于栈底附近的项目。另外,从栈中删除项目的顺序和向栈中添加项目的顺序是相反的。有很多数据处理和分析问题适合使用栈来解决。人们使用栈来分配和访问计算机内存、保存命令行参数和函数参数、解析表达式、反转数据项、保存与回溯 URL,等等,生活中我们经常接触到的栈是浏览器保存我们浏览网页顺序的机制以及返回功能。书中一个形象化的例子是叠盘子:
可以将栈想象为自助餐厅中的一叠盘子。要想产生一叠盘子,可以先向柜台上放一个盘子,然后向第一个盘子上面再放一个盘子,并一直重复这个操作。要想减少这叠盘子的数量,就要从顶端拿走一个盘子。你可以在任何时候增加或减少一个盘子,但是必须一直从顶端增加或减少。
附上一个list实现栈的类代码:
class Stack:
def __init__(self):
self.items=[]
def isempty(self):
return self.items==[]#一个判断函数,如果等是true
def push(self,item): #把数据压入栈
self.items.append(item)
def push1(self,i): #有容量限制的 栈
if len(self.items)<100: #100为阈值
self.items.append(item)
else:
print('Stack is Full')
def pop1(self): #弹出数据
return self.items.pop()
def pop(self):#这样更好一些
if self.items!=[]:
return self.items.pop()
else:
print('Stack is empty')
def peek(self): #窥视数据
return self.items[-1]
#return self.items[len(self.items)-1]
def size(self):
return len(self.items)
def show(self):
return self.items
#实例化:
s=Stack()
s.push(4)
s.push('lcf')
s.push('56')
print(s.size())
print(s.peek())
print(s.pop())
print(s.isempty())
输出:
3
56
56
False
队列
队列是一个项目的有序集合,它的特性是 FIFO(first in, first out,先入先出) ,既可以向队列的一端添加项目,又可以从队列的另一端删除项目。在队列中,可以向队列后端添加项目,这样项目会依次向前移动,并在前端被移出队列。排队就是很典型的队列过程。有很多数据处理和分析问题适合使用队列来解决。人们使用队列来处理打印机上的打印任务、控制计算机进程等待资源、优化队列和网络流程,等等。
限制Python的列表不能操作中间的数就能实现简单的队列了:
class Queue:
def __init__(self):
self.items =[]#同样先应用无序表
def isEmpty(self):
return self.items==[]#如果等是true
def enqueue(self, item): #加数据
self.items.append(item)
def dequeue(self): #删除数据
if self.items!=[]:
return self.items.pop()
else:
print('Queue is empty')
def size(self): #队列长度
return len(self.items)
def show(self):
return self.items
#调用:
q= Queue()
q.enqueue(5)
q.enqueue('lcf')
print(q.size())
q.dequeue()
print(q.show())
输出: 2 [5]
图与树
图是一组结点(也称为顶点)和连接结点的边的集合。边可以是有方向的,表示两个结点之间的方向,也可以是无方向的,仅表示两个结点之间的连接。边还可以具有权重,表示两个结点之间的关系,根据具体问题的情况,权重可以不同。有很多数据处理和分析问题适合使用图来解决。人们使用图来表示供应商、客户和产品之间的关系,或者实体之间的关系,还使用图来表示地图,以及不同类型资源的储量和需求量。
从数据结构意义上说,树是图的一种特殊形式,图是更大的集合,树是图的子集合,树由一组层次化的结点和边组成。在树中,有一个最顶层的结点,称为根结点。根结点可以有任意数量的子结点,每个子结点也可以有任意数量的子结点。一个子结点只能有一个父节点。如果每个结点有多达两个子结点,那么这样的树就被称为二叉树。二叉树是树中应用最广的。有很多数据处理和分析问题适合使用树来解决。人们使用树来建立计算机中的文件系统、管理层次化的数据、使信息更易于检索,以及表示句子中的短语结构等。
《Python数据分析基础》这本书到这里就结束了,当然我们的学习才启航,当然我们跟着这本书学到这里,应该收获良多。这一章知识点很多,后续学习数据分析还会经常用到本章提到的库或者数据结构,因为今天周六,因此笔记也写得比较长,当然很多库还能深入讲的内容没有讲,之后有机会会增加各种库的深入笔记。书中有一段话我觉得能作为继续学习的导引:
一旦你意识到可以高效地完成那些枯燥无味、浪费时间、容易出错的手工不可能完成的任务,就会感到一种激情流遍全身,迫不及待地希望使用 Python 去完成更多的问题和任务。这就是我希望你去做的事情,从这里启航,选择一个重要的问题或任务去攻克,直到你的代码正确运行,到达胜利的彼岸。
本篇笔记的GitHub同步项目于readingForDS。关于本系列笔记有任何建议欢迎留言讨论。