《利用python进行数据分析》是一本利用python的Numpy、Pandas、Matplotlib库进行数据分析的基础介绍,非常适合初学者。
重要的python库
NumPy
http://numpy.org
Pandas
http://pandas.pydata.org
matplotlib
http://matplotlib.org
IPython 和 Jupyter
http://ipython.org
http://jupyter.org
Scipy
http://scipy.org
scikit-learn
http://scikit-learn.org
statsmodels
http://statsmodels.org
nbviewer
https://nbviewer.jupyter.org/
软件安装和环境配置:
安装Anaconda:https://www.anaconda.com/
下载安装包或者pip install jupyter notebook
Jupyter notebook用法:
内省
?, 对象前后加?号可以显示对象概要信息,针对魔术字也是生效的,即可以查看魔术字的参数
??, 使用??可以显示函数源码
?,可以作为通配符使用,与*结合可以查询符合规范的名称
Ipython magic
https://ipython.readthedocs.io/en/stable/interactive/magics.html
%,一个%只作用于命令行
%%,两个%表示作用于命令框
%run
%run script_name.py
可以运行外部脚本
%run -i script_name.py
使用Ipython命名空间已有的变量
%load script_name.py
可以将脚本加载到单元代码
ctrl+c
终止程序运行
%paste和%cpaste
将剪贴板代码黏贴过来,或者会提醒检查。
没用成功过?
%timeit
检查一段python语句的执行时间,计算平均值
%time
报告单个语句的执行时间
%automagic
可以关闭魔术字前面的%符号
%quickref
显示Ipython快速参考卡
%magic
显示所有magic
%debug
从报错底部进入交互调试器,通过u和d可以切换堆栈的不同层级
%pdb
出现任意错误自动进入调试器
%reset
重启变量/名称,命名空间
%who, %who_ls, %whos
展示命名空间定义的变量
%xdel variable
删除变量
%matplotlib, %matplotlib inline
设置matplotlib与Ipython集成,后者是用于jupyter notebook中
%xmode
控制错误栈上下文的数量,有Plain和Verbose两种模式,前者同Cpython,后者是Ipython独有
%hist,可打印全部、部分历史输入记录
IPython扩展
ipython是一个python的交互式shell,是jupyter notebook的内核。
搜索历史命令
%run some.py
以后可输入%run s然后用上下箭头查询历史命令
输入和输出变量引用
_和__分别表示最近的第一个和第二个命令执行结果的输出
_number表示第number行的输出结果
_inumber表示第number行的输入变量
exec(_i27)可以直接执行一次第27行命令
与操作系统交互
可以直接输入win或shell命令
!cmd 执行cmd命令
output = !cmd args 运行命令并保存输出结果
%alias alias_name cmd 起别名
%bookmark 使用IPython的目录书签系统。 %bookmark pydata /home/ccc/code/pydata
%cd dir 更改目录
%pwd 返回当前工作目录
%pushd dir 将当前目录放在堆栈上,并更改伪目标目录
%popd 切换到堆栈顶部弹出的目录
%dirs 返回包含当前目录堆栈的列表
%dhist 打印访问目录的历史记录
%env 以字典形式返回系统环境变量
%matplotlib 配置matplotlib集成选项
调试程序
出问题后,通过%debug进入堆栈最底层,通过u和d可以切换堆栈的不同层级
也可用%pdb直接让程序出错时进入调试模式
run -d test.py,可以进入单步调试模式, s表示进入脚本,可以设置断点,可以用c继续运行程序
b linenumber, 可以设置断点
b path/file.py:number 在指定文件行设置断点
n, next意思
c, continue意思
s,step单步意思
!variable, 变量前面加!可以显示变量值
u/d, 在调用栈中上下移动
a, args显示当前函数的参数
debug statement, 在新的调试器中调用语句statement
l statement, 显示当前堆栈的当前位置和上下文
w, where意思,在当前位置打印带有上下文的完整堆栈回溯
h, help显示命令列表
help command, 显示command命令的文档
q,quit退出调试器
%run -d test.py, 可以直接进入调试器
%run -d b2 test.py, 加断点
pdb.set_trace
from IPython.core.debugger import Pdb
def set_trace():
Pdb(color_scheme="Linux").set_trace(sys.__getgrame().f_back)
可以在程序任何地方调用set_trace(),比如在抛出异常前调用,可以进入调试模式
pdb.runcall
from IPython.core.debugger import Pdb
def debug(f, *args, **kwargs):
pdb = Pdb(color_scheme="Linux")
return pdb.runcall(f, *args, **kwargs)
可以单独调试一个函数
def f(x, y, z=1):
return (x+y)/z
debug(f, 1,2,z=3)就可以进入调试模式
测试代码运行时间: %time和%timeit
%time,执行一次
%timeit,多次执行取平均值,可以精确到ns级别
分析代码性能:%prun, %run -p
python有个cProfile模块可以用于分析程序性能。
举例:
python -m cProfile -s cumulative test.py #-s指定排序字段
Ipython分析
%prun -l 7 -s cumulative function()
可以分析单个函数
%run -p -s cumulative test.py
%%prun 可以分析整个代码块。
其他第三方库:SnakeViz,使用d3.js生成配置文件结果的交互式可视化
%lprun,这是第三方模块,需要自己配置,可以逐行分析函数代码性能,而不仅仅限制于函数级别
配置方式:
方法1:c.TerminalIPythonApp.extensions = ['line_profiler']
方法2:%load_ext line_profiler
使用方式:
%lprun -f add_and_sum -f call_function call_function()
重载模块
有时候被装载的模块代码被修改,这时除了退出重新进入装载外,还有下面方法:
import some_lib
import importlib
importlib.reload(som_lib)
Ipython有个dreload(some_lib)可以用
代码设计技巧
扁平优于嵌套
适当的大文件比零散的多个小文件好管理
配置文件:
ipython profile create #可以形成ipython配置文件
文件路径C:\\Users\\guangxinwang\\.ipython\\profile_default\\ipython_config.py
也可以创建一个新的配置文件,并自己使用:
ipython profile create secret_project
ipython --profile=secret_project
jupyter notebook的配置文件:
jupyter notebook --generate-config
默认路径.jupyter/jupyter_notebook_config.py
jupyter notebook --config=~/.jupyter/my_custom_config.py
配置内容摘要有:
主题
启动扩展模块等
自定义魔术函数等
NumPy基础:数组和向量化计算
NumPy的重要性:
1、NumPy的设计对于含有大量数组的数据非常有效;
2、NumPy在内部将数据存储在连续的内存块上,NumPy的算法库是C语言写的,不需要任何类型检查。而且占用的内存量也小
3、NumPy可以针对全部数组进行复杂计算而不需要写python循环
导入:推荐import numpy as np
NumPy的核心——N维数组对象ndarray
一个ndarray是一个通用的多维同类数据容器,即它包含的每一个元素都是相同类型
属性:
shape
表示ndarray的维度
dtype
表示ndarray的数据类型,ndarray的默认数据类型是float64
ndim
表ndarray数组的维度
形成ndarray数组的方法
array, 将输入数据转换成ndarray数组,如果不指定类型,会自动推断
asarray, 同上,只是如果输入已经是ndarray就不再复制
arange, range函数,返回一个数组。np.arange(0.0, 1.0, 0.01),返回从[0,1)间隔0.01的共100个dnarray数组
ones, 全1数组
ones_like, 根据所给数组形成全1数组,即shape同所给数组,值全1
zeros, 全零数组
zeros_like,参照数组形成全0数组
empty, 空输入,内容随机
empty_like,参照数组形成空数组
full, 形成指定数值的数组
full_like,参照指定数组形成指定数值的数组
eye, identity, 形成对角线全是1的数组
random.randn,形成随机数,满足正态分布
random.randint,返回随机整数
ndarray的数据类型
int/float/complex/bool/object/string_/unicode_
长度有8/16/32/64/128/256等等
默认int为32,float为64
类型转换方法astype
my_int_arra.astype(float)
astype一定会形成新的数组
数组运算
*,-,+,/,** 逐个元素相乘,减,加,除,幂
>,<,逐个元素比较大小
索引和切片
切记:
NumPy的切片不生成新数组,而是原数组的引用,相关操作会直接作用在原数组上面,这样做好处是节省内存
如果希望新创建数组需要显示的用copy方法,比如arr[5:8].copy()
下面2种方法效果相同:
arr2d[0][2]
arr2d[0,2]
可以对切片后的数组直接赋值
寻址:
对于一个N维数组a
当需要定位到一个元素时需要同时输入N个坐标才能取到单个元素的值。
每少一个坐标,取到的值就会多一个维度。少的一个坐标轴就会返回该坐标轴上面的所有数据;
每多一个坐标,就可以少一个维度的不确定性。
降维就是通过指定一个坐标轴,取该坐标轴上面其他维度的数据
在一个轴上面切片是可以取到同维度的数组的
布尔索引
假设a数组维度为3*4即a(3,4)
a>0,会形成同样维度的bool类型数组,里面的每个值都会是True或False
可以用bool类型的数组作为索引,对同维度的数组进行取值,比如a(3,4),b是一维3元素数组,这样a[b>0]可以对a的行取值
同理,更高维度也可以。比如a(5,7,4),b(7,4)执行a[:b>0]会形成一个(5,x)的维度数组,x取决于b>0的个数。注意这里会做降维处理。
注意,两者维度不同时会报错。
这里支持用==,>,<,!=,~取反,&,|等操作
and or操作在这里不生效,需要用&/|
利用布尔索引可以对一个数组的指定元素进行操作,比如a[a>0]=0,就可以将a数组里面所有大于0的元素赋值为0,而操作后a的维度不变。
再举例:a(5,7,4),b(7,4),执行a[:,b>0]=0可以对a中所有行执行同样赋值操作,结束后a还是(5,7,4)维度不变
神奇索引
可以用数组作为索引值
举例:
arr(8,4)数组,arr[[4,3,0,6]]会返回第4、3、0、6行的数据,也支持负数索引
arr[[4,3,0,6],[1,2,3,0]]返回的是一个一维数组取值(4,1),(3,2),(0,3),(6,0)
行与列索引
行索引arr[:2]
列索引arr[:,:2]
转置和转轴
reshape(),变换形状
np.arange(8).reshape((2,4)) #变为2*4数组
np.arange(8).reshape((2,-1)) #作用同上,传入-1表示让numpy自己推断数组维度
np.arrage(8).reshape(other_arr.shape) #shape也可以作为参数传入
扁平
np.arange(8).reshape((2,-1)).ravel() #ravel是分散意思,会扁平成一个一维数组,不会形成副本
np.arange(8).reshape((2,-1)).flatten() #flatten作用同ravel,区别是这个会形成一个新的副本
arr.T,转置,是一种特殊的转轴,对于多维数组的转轴,就是将所有的轴完成倒序操作
np.dot(arr, arr.T),计算矩阵内积
arr.transpose()转轴,参数是轴索引
转轴计算方法:
第一步先变形,比如一个arr(2,3,4)矩阵,如果轴0和轴1转轴,该矩阵将变为arr(3,2,4)
第二步填值,新的变形后的矩阵的每个元素比如arr[i,j,k]就等于原来数组的arr[j,i,k]
arr.swapaxes()方法可以将轴进行调整重组成新数组,也是转轴的一个方法,仅支持2个轴交换
通用函数ufunc
一元通用函数:
abs,fabs, 绝对值
sqrt,平方根
square, 平方
exp, e的指数值
log,log10,log2,log1p,分别是以e,10,2为底,最后一个是log(1+x),默认以e为底
sign, 求符号值,1,0,-1
cell,最高整数,遇到小数往上取整
floor,往下取整
rint,保留整数位,且保留dtype
modf, 分别返回小数和整数部分
isnan,判断是否为NaN,不是一个数值
isfinite,isinf, 是否有限还是无限
cos,cosh,sin,sinh,tan,tanh三角函数
arccos,arccosh,arcsin,arcsinh,arctan,arctanh,反三角函数
logical_not,对数组元素按位取反,同~arr
二元通用函数:
add,元素对应相加
subtract,减
multiply,乘
divide,floor_divide,除,整除
power, 幂
maximum,fmax,最大值
minimum, fmin,最小值
mod,取模求余数
copysign,将第一个数组的符号值改成第二个数组的
greater,greater_euqal,less,less_equal,equal,not_equal,逐元素比较,返回布尔型
logical_and,logical_or,logical_xor,逻辑与,或,异或
面向数组编程
np.where
等同于python的 x if condition else y
格式:
new_arr = np.where(condition, xarr, yarr)
解释:
condition是条件判断,如果为真元素取xarr中值,false取yarr中的值
举例:
np.where(arr>0, 2, -2)
arr中元素如果大于0会被置为2,小于0会被置为-2
统计方法
数组方法和np方法都可以
arr.mean()或np.mean(arr),平均值
mean(axis=0),计算给定轴的平均值,就是把该轴上面的值求和然后再平均,这样会导致该轴的维度扁平为1维。
mean(0),不带axis也可以
如果是一个三维数组(2,3,4),mean(axis=2)会把轴2扁平化,形成(2,3)数组
sum(),求和
cumsum()累计求和
cumsum(axis=0),沿着行做累计求和,就是从第2行开始,每个元素都是上一行对应列加本行对应列的和。即把所有axis轴数据都加起来。
std()标准差
var()方差
cov()协方差
min(),max()最小最大值
argmin(),argmax(),最小最大值得位置
cumprod(),从1开始元素累积积运算,cumsum是和运算
布尔值数组方法
(arr > 0).sum()可以计算True数量
any(),任意为True就为True
all(),所有为True才为True
排序
sort(),可以沿着axis排序如sort(0)就是沿着x轴对y轴进行排序,就是只对y轴排序
唯一值
np.unique()
针对一维数组,返回的是去重后的数组,并且还完成排序
np.in1d(arr1, arr2)
判断数组1中值是否在数组2中,返回bool类型的数组,长度同arr1
intersect1d(x, y)
x,y交集并排序
union1d(x,y)
x,y并集并排序
setdiff1d(x, y)
差集,在x但不在y中的x的元素
setxor1d(x,y)
异或,在x或y中,但不同时在x和y中
装载与存储
np.save(file, arr, allow_pickle=True, fix_imports=True)
np.load(file,mmap_mode=None,allow_pickle=False,fix_imports=True,encoding='ASCII',)
默认都是二进制形式存取的
文件后缀默认是npy
np.savez(file, *args, **kwds)
压缩存储
举例:
np.savez("array_arhive.npz", a=arr1, b=arr2)
此时用np.load会返回一个字典类型
arch = np.load("array_archive.npz")
可以用arch['a']或arch['b']取到存储的数组
np.savez_compressed(file, *args, **kwds)
将新的数组存入已经压缩好的文件中
线性代数
*, 表示矩阵逐元素乘法
dot(),表示矩阵点乘
arr1.dot(arr2)
np.dot(arr1,arr2)
arr1 @ arr2
@也是点乘,属于一元运算符
numpy.linalg库函数(linear algebra)线性代数
diag, 用于将一个方阵的对角元素转换为一维数组,或者把一维数组转换为方阵
dot,点乘
trace,计算对角元素和
det,计算矩阵的行列式
eig,(eigen)计算方阵的特征值和特征向量
inv,(inverse)计算方阵的逆矩阵
pinv,计算矩阵的Moore-Penrose伪逆
qr,计算QR分解
svd,计算奇异值分解(SVD)
solve,求解x的线性系统Ax = b, 其中A是方阵
lstsq,(least square)计算Ax=b的最小二乘解
伪随机数的形成
np.random.normal(size=(4,4))
形成4*4的正态分布数组
np.random.seed(1234)
更改伪随机种子,作用于全局。随机种子类似于产生随机数的初始值,随机种子相同情况下产生的随机数也相同,所以要产生不同随机数需要重置随机种子。
np.random.RandomState(1234)
创建伪随机生成器,独立于全局随机种子的影响
rng = np.random.RandomState(1234)
rng.randn(10)
常用函数列表:
seed, 种子
permutation, 返回一个序列的随机排列,或返回一个乱序的整数范围序列
shuffle, 随机排列一个序列
rand,从均匀分布中抽取样本
randint, 根据给定的由低到高的范围抽取随机整数
randn, 从均值0方差1的正态分布中抽取样本
binomial, 从二项分布中抽取样本
normal, 从正态分布中抽取样本
beta,从beta分布中抽取样本
chisquare, 从卡方分布中抽取样本
gamma,从伽马分布中抽取样本
uniform,从均匀[0,n)中抽取样本,np.random.uniform(0,10000,size=50)
举例1:
import matplotlib.pyplot as plt
nsteps = 1000
draws = np.random.randint(0, 2, size=nsteps) #从0,1中随机抽取1000次
steps = np.where(draws > 0 , 1, -1) #把0,1格式化成-1和1
walk = steps.cumsum() #对数组做累计求和
plt.plot(walk) #打印折线图
walk.min() #求连续走最小或最大步数
(np.abs(walk) >= 10).argmax() #求第一次连续一个方向走10步的位置
举例2:
nwalks = 5000
nsteps = 1000
draws = np.random.randint(0, 2, size=(nwalks,nsteps)) #形成一个二维数组
steps = np.where(draws > 0, 1, -1)
walks = steps.cumsum(1) #沿着1轴做累计和
hits30 = (np.abs(walks) >= 30).any(1) #沿着1轴做任何一个元素为True就总结果为True,返回的hits30是一个5000行的一维数组,元素都是True和False
crossing_times = (np.abs(walks[hits30]) >= 30).argmax(1) #walks[hits30]获取hits30中为True的行,比如有3000行,argmax沿着1轴求最大值第一次出现的位置索引
crossing_times.mean() #请第一次出现位置的平均值
NumPy进阶:
数组构成
NumPy数组包含下面内容:
指向数据的指针
数据类型dtype
表示形状的元组
步长元组
比如np.ones((2,3,4),dtype=np.int32).strides是(48, 16, 4)
解析:
最后一个4是数据长度为4字节
第一个48表示344,表示每行的跨度是48字节
第二个16表示4*4,表示最小一维数组的跨度是16字节
dtype层次结构和类型判断
generic -> number -> integer -> unsigned int 各种字节的无符号数,下同
| | -> signed int
| -> inexact -> floating
| -> complex
-> character -> string _
| -> unicode_
-> bool _
-> object_
np.issubdtype(obj.dtype, np.interger)
通过issubdtype方法可以判断数组类型是否属于某一类型
np.float64.mro()
可以通过mro方法查看该类型的父类
C顺序和F顺序
C顺序/行方向顺序,即C语言顺序
首先遍历更高维度(在轴0上行进之前先在轴1上行进)
F顺序/列方向顺序,即Fortran语言顺序
首先遍历高低维度
NumPy默认是C顺序,比如ravel()默认参数是C,如果ravel('F')就会返回F顺序的数据
数组的连接和分隔
arr1,arr2都是(2,3)数组,那么np.concatenate([arr1,arr2], axis=0)就会连接成一个(4,3)数组, axis=1会连接成(2,6)数组
arr是一个(5,2)数组,first, second, third = np.split(arr, [1,3]),会被分隔成3个数组,分隔位置就是1和3,first是一维,secode是1和2行的2维数组,third是2维
所有连接分隔函数:
concatenate, 通用连接函数
vstack, row_stack, 按行堆叠,沿轴0
hstack, 按列堆叠
colum_stack, 类似hstack,但会先把一维数组转换为2维列向量
dstack, 按深度堆叠数组,沿着轴2
split, 沿指定轴分隔数组
hsplit,vsplit,沿轴0和轴1分隔
r_和c_堆叠助手:
arr = np.arange(6)
arr1 = arr.reshape((3,2))
arr2 = np.random.randn((3,2))
np.r_[arr1, arr2] #将返回一个(6,2)数组,类似vstack
np.c_[np.r_[arr1,arr2], arr] #返回一个(6,3)数组,类似hstack
数据重复
repeat
arr.repeat(2,axis=0),将arr所有元素重复2遍,并沿着0轴做扩展。如果arr是(2,2),重复后是(4,2)
如果不指定axis,会被扁平化为一维数组
arr.repeat([2,3], axis=0),如果arr是(2,2),重复后为(5,2),传入[2,3]数组分别指定第一行重复2次,第二行重复3次
tile
俗称瓷砖铺设,将原始数组理解成1个大瓷砖,然后重复这个瓷砖
比如arr(2,2)
np.tile(arr, 2),将变为(2,4),默认在列方向扩展
np.tile(arr,(3,2)),将变为(6,4)
tile和repeat区别是前者是将整个数组作为一个整体进行复制,而后者是对每个元素进行复制。所以后者重复的行或列会连续出现,而前者是间隔出现
神奇索引等价操作
take
take可以根据索引取对应轴的数据
比如arr是(2,4),inds=[2,0,2,1]
那么arr.take(inds, axis=1)就会得到(2,4)数组,4列分别是原数组的第2、0、2、1列
put
向数组赋值,put需要注意是不接受axis参数的,而是会做扁平化处理。
比如arr.put(inds, [1,2,3,4])就会把inds里面索引的元素分别赋值为1、2、3、4.注意索引会做扁平化处理。默认按C顺序进行编号
广播机制
广播需要慎重,仔细,容易出错
广播规则:
如果对于每个结尾维度(即从尾部开始的),轴长度都匹配,两个二维数组就是可以兼容广播的。之后,广播会在丢失的轴上进行。
如果不是在轴0广播,而是其他轴上面广播,要求广播的轴维度为1。如果有多个轴为1,那么所有维度为1的轴都会广播。
举例:
arr是(4,3),那么arr.mean(0)是4,arr.mean(1)是3
那么arr-arr.mean(0)就是(4,3)与3的运算,可以进行行方向的广播
arr-arr.mean(1)就是(4,3)与4的运算,由于3和4不同,无法进行列方向的广播,这时进行arr.mean(1).reshape(4,1)变形,就是(4,3)与(4,1)运算,因为是1可以广播
同理,多维数组也是可以广播的,比如(3,4,2)和(4,2)数组是可以沿着轴0广播。
np.newaxis
reshape可以加一个1维的轴。替代方案用np.newaxis插入一个新轴。
arr如果是(3,4),变成(3,1,4)方法:arr[:,np.newaxis,:]
其实np.newaxis就是None,直接用None其实也可以
多维数组的广播
arr是(2,3,4),和数组(2,1,4)进行运算时,会沿着1维的轴1进行广播。
举例:求arr-轴2平均值
arr - arr.mean(axis=2)[:,:,np.newaxis]
举例:一个通用函数
def demean_axis(arr, axis=0):
indexer = [slice(None)] * arr.ndim #slice(None)等同于[:],将切片扩展到多维[:,:,:]
indexer[axis] = np.newaxis #等同于[:,newaxis,:]
return arr - arr.mean(axis)[indexer]
通过数组索引完成广播赋值
arr = np.zeros((4,3))
arr[:] = 5 #arr所有元素将全部赋值为5
col = np.array([1,2,3,4])
arr[:] = col[:, np.newaxis] #col[:, np.newaxis]可以转为(4,1)数组, arr[:]索引全部列,最终arr所有3列的值相同都是1、2、3、4
arr[:2] = [[8],[9]] # [[8],[9]]是一个(2,1)数组,arr的第一行全是8,第2行全是9
高阶ufunc用法
在普通的ufunc运算后面可以再跟高阶的ufunc函数,比如np.add.reduce(arr)。
reduce(x)
聚合操作
举例:
arr=np.arange(10)
np.add.reduce(arr) #等同于arr.sum()就是求和
np.logical_and.reduce(arr[:,:-1] < arr[:,1:], axis=1)
等同于对每行求all方法。
accumulate(x)
累计聚合,两两相加
举例:
np.add.accumulate(np.arange(15).reshape((3,5)), axis=1) 会沿着轴1,对轴0做累计求和
reduceat(x, bins)
group by缩聚方法
举例:
np.add.reduceat(np.arange(10),[0,5,8]) #会对[0,5],[5,8],[8:10]分3组聚合
也可以加axis参数
outer(x,y)
操作应用于x,y所有元素对,执行结果的维度是x和y的维度和,比如x和y是一维数组,那么运算完后就变成2维数组。
举例:
np.multiply.outer(np.arange(4),np.arange(5))
得到一个(4,5)二维数组
用python编写ufunc方法
下面2个方法是用python编写ufunc方法,因为都是用python编写的,所以运行速度会很慢,比C语言的差可能1000倍
numpy.frompyfunc
举例:
def add_element(x, y):
return x + y
add_them = np.frompyfunc(add_element, 2,1) #2表示输入参数2个,1表示输出参数1个
add_them(np.arange(8), np.arange(8)) #返回结果是一个object类型,而不是numpy类型对象
numpy.vectorize
这个可以指定返回值类型
举例:
add_them = np.vectorize(add_element, otypes=[np.float64]) #add_element是一个自定义python函数,otype是定义函数输出类型
add_them(np.arange(8), np.arange(8))#返回float64类型
结构化
numpy用的是同构数据,即所有数据类型都是dtype,同一类型。如果想表示异构或者表格数据也有方法。
方法:
使用(field_name, field_data_type)作为元组的列表传给构建数组时的dtype值
dtype=[('x',np.float32),('y',np.int32)]
arr=np.array([(1.5,6),(np.pi,-2)],dtype=dtype)
arr将是一个一维数组,而且元素是2个。但是可以用arr['x']或者arr['x'][0]等方式来取值
嵌套和多维字段
dtype=[('x',np.int64,3),('y',np.int32)]
arr=np.zeros(4,dtype=dtype)
这样arr['x']或者arr[0]['x']等方式访问3个元素
dtype=[('x', [('a', 'f8'), ('b', 'f4')]), ('y',np.int32)
也可以这样嵌套定义
排序
sort排序
arr.sort()是原位排序,不形成新数组
np.sort(arr)会形成新数组
所有排序都是升序排序,如果要降序,可以用arr[:,::-1]方式获取
间接排序
argsort
返回排序后的索引值
np.array([5,0,1,3,2]).argsort()返回的是array([1,2,4,3,0])这个数组是索引,用arr[index]方式可以获取排序后的数组
按第一行重新排序:
arr[:,arr[0].argsort()] #arr[0].argsort()返回比如array([2, 1, 0, 4, 3], dtype=int64),这样类似arr[:,[2,1,0,4,3]],重新排列列
numpy.lexsort
和argsort类似,也是返回index。区别是numpy.lexsort可以完成多键排序
举例:
sorter = np.lexsort((first_name, last_name))
注意,这里会先根据last_name进行排序,在有相同值时,会比较对应列的值大小,来决定最终排序。
返回结果也是索引值,比如[1,2,3,0,4]
稳定排序
针对的是有相同元素的排序,当元素相同时,靠前的元素会排在前面
举例:
value.argsort(kind='mergesort')
kind有3种可用排序选项:
种类 速度 是否稳定 工作空间 最差情况
'quicksort' 速度最快 不稳定 O O(n^2)
'mergesort' 速度中等 稳定 n/2 O(n log n)
'heapsort' 速度低 不稳定 O O(n log n)
分组排序
numpy.partition和numpy.argpartition
可用完成分段/分组排序,后者同argsort返回的是等价信息索引
举例:
np.partition(arr,3),会将arr分成2组,前面3个元素一组,后面的一组,其中前面3个是最小的3个元素。注意只是组间有排序,具体到组内元素是随机的不排序。
在已排序数据中寻找插入位置
numpy.searchsorted
注意,必须是已经排序的数组
举例:
arr.searchsorted([0,8,11,16]) #返回这4个值在arr数组中的插入位置索引
可以用于分组:
group=np.array([0,100,1000,5000,10000])
group.searchsorted(data) #将data中元素归类到group中的区间
numba库
http://numba.pydata.org
建议好好研究下,该库使用LLVM将python代码编译成机器码,大大加快python执行速度
举例1:
from numba import vectorize
@vectorize
def nb_add(x, y):
return x + y
x = np.arange(10)
nb_add(x, x)
nb_add.accumulate(x, 0)
举例2:
from numba import float64, njit
@njit(float64(float64[:], float64[:]))
def mean_distance(x, y):
return (x - y).mean()
高阶数组的输入和输出
内存映射文件mmap
mmap = np.memmap('mymmap', dtype='float64', mode='w+', shape=(10000,10000))
和打开文件类似,需要指定文件名、数据类型、打开模式、形状
该文件会被映射到连续内存中,可以对其操作
mmap.flush() #将数据刷回到磁盘中