04-Python科学计算:用NumPy快速处理数据

1.第三方库 NumPy和列表list.
Python 中一个非常重要的第三方库 NumPy。它不仅是 Python 中使用最多的第三方库,而且还是 SciPy、Pandas 等数据科学的基础库。它所提供的数据结构比 Python 自身的“更高级、更高效”,可以这么说,NumPy 所提供的数据结构是 Python 数据分析的基础。
实际上,标准的 Python 中,用列表 list 保存数组的数值。由于列表中的元素可以是任意的对象,所以列表中 list 保存的是对象的指针。虽然在 Python 编程中隐去了指针的概念,但是数组有指针,Python 的列表 list 其实就是数组。这样如果我要保存一个简单的数组[0,1,2],就需要有 3 个指针和 3 个整数的对象,这样对于 Python 来说是非常不经济的,浪费了内存和计算时间。
2.使用 NumPy 让你的 Python 科学计算更高效.
这是因为列表 list 的元素在系统内存中是分散存储的,而 NumPy 数组存储在一个均匀连续的内存块中。这样数组计算遍历所有的元素,不像列表 list 还需要对内存地址进行查找,从而节省了计算资源。另外在内存访问模式中,缓存会直接把字节块从 RAM 加载到 CPU 寄存器中。因为数据连续的存储在内存中,NumPy 直接利用现代 CPU 的矢量化指令计算,加载寄存器中的多个连续浮点数。
另外 NumPy 中的矩阵计算可以采用多线程的方式,充分利用多核 CPU 计算资源,大大提升了计算效率。当然除了使用 NumPy 外,你还需要一些技巧来提升内存和提高计算资源的利用率。一个重要的规则就是:避免采用隐式拷贝,而是采用就地操作的方式。举个例子,如果我想让一个数值 x 是原来的两倍,可以直接写成 x*=2,而不要写成 y=x*2。这样速度能快到 2 倍甚至更多。
在 NumPy 里有两个重要的对象:ndarray(N-dimensional array object)解决了多维数组问题,而 ufunc(universal function object)则是解决对数组进行处理的函数。
2.1.ndarray 对象.
ndarray 实际上是多维数组的含义。在 NumPy 数组中,维数称为秩(rank),一维数组的秩为 1,二维数组的秩为 2,以此类推。在 NumPy 中,每一个线性的数组称为一个轴(axes),其实秩就是描述轴的数量。

import numpy as np
a=np.array([1,2,3])
b=np.array([[1,2,3],[4,5,6],[7,8,9]])
b[1,1]=10
print(a.shape)  #通过函数 shape 属性获得数组的大小.
print(b.shape)  #通过 dtype 获得元素的属性.
print(a.dtype)
print(b)

2.2.结构数组.
首先在 NumPy 中是用 dtype 定义的结构类型,然后在定义数组的时候,用 array 中指定了结构数组的类型 dtype=persontype,这样你就可以自由地使用自定义的 persontype 了。比如想知道每个人的语文成绩,就可以用 chineses = peoples[:][‘chinese’],当然 NumPy 中还有一些自带的数学运算,比如计算平均值使用 np.mean。

import numpy as np
persontype = np.dtype({
    'names':['name', 'age', 'chinese', 'math', 'english'],
    'formats':['S32','i', 'i', 'i', 'f']})
peoples = np.array([("ZhangFei",32,75,100, 90),("GuanYu",24,85,96,88.5),
       ("ZhaoYun",28,85,92,96.5),("HuangZhong",29,65,85,100)],
    dtype=persontype)
ages = peoples[:]['age']
chineses = peoples[:]['chinese']
maths = peoples[:]['math']
englishs = peoples[:]['english']
print(np.mean(ages))
print(np.mean(chineses))
print(np.mean(maths))
print(np.mean(englishs))

2.3.ufunc 运算.
ufunc 是 universal function 的缩写,它能对数组中每个元素进行函数操作。NumPy 中很多 ufunc 函数计算速度非常快,因为都是采用 C 语言实现的。
2.4.连续数组的创建.
NumPy 可以很方便地创建连续数组,比如用 arange 或 linspace 函数进行创建.都是创建等差数组。

x1=np.arange(1,11,2)
x2=np.linspace(1,9,5)
print(x1)
print(x2)

这两个数组的结果 x1,x2 都是[1 3 5 7 9]。结果相同,但是创建的方式是不同的。arange() 类似内置函数 range(),通过指定初始值、终值、步长来创建等差数列的一维数组,默认是不包括终值的。linspace 是 linear space 的缩写,代表线性等分向量的含义。linspace() 通过指定初始值、终值、元素个数来创建等差数列的一维数组,默认是包括终值的。
2.5.算数运算.
通过 NumPy 可以自由地创建等差数组,同时也可以进行加、减、乘、除、求 n 次方和取余数。

x3=np.arange(1,11,2)
x4=np.linspace(1,9,5)
print(np.add(x3,x4))
print(np.subtract(x3,x4))
print(np.multiply(x3,x4))
print(np.divide(x3,x4))
print(np.power(x3,x4))
print(np.remainder(x3,x4))
print(np.mod(x3,x4))
#在取余函数里,你既可以用 np.remainder(x1, x2),也可以用 np.mod(x1, x2),结果是一样的。

3.统计函数.
想对一堆数据有更清晰的认识,就需要对这些数据进行描述性的统计分析,比如了解这些数据中的最大值、最小值、平均值,是否符合正态分布,方差、标准差多少等等。
3.1.计数组 / 矩阵中的最大值函数 amax(),最小值函数 amin().

import numpy as np
a=np.array([[1,2,3],[4,5,6],[7,8,9]])
print(np.amin(a))
print(np.amin(a,0))
print(np.amin(a,1))
print(np.amax(a))
print(np.amax(a,0))
print(np.amax(a,1))

amin() 用于计算数组中的元素沿指定轴的最小值。对于一个二维数组 a,amin(a) 指的是数组中全部元素的最小值,amin(a,0) 是延着 axis=0 轴的最小值,axis=0 轴是把元素看成了[1,4,7], [2,5,8], [3,6,9]三个元素,所以最小值为[1,2,3],amin(a,1) 是延着 axis=1 轴的最小值,axis=1 轴是把元素看成了[1,2,3], [4,5,6], [7,8,9]三个元素,所以最小值为[1,4,7]。同理 amax() 是计算数组中元素沿指定轴的最大值。
3.2.统计最大值与最小值之差 ptp().

import numpy as np
a=np.array([[1,2,3],[4,5,6],[7,8,9]])
print(np.ptp(a))
print(np.ptp(a,0))
print(np.ptp(a,1))

对于相同的数组 a,np.ptp(a) 可以统计数组中最大值与最小值的差,即 9-1=8。同样 ptp(a,0) 统计的是沿着 axis=0 轴的最大值与最小值之差,即 7-1=6(当然 8-2=6,9-3=6,第三行减去第一行的 ptp 差均为 6),ptp(a,1) 统计的是沿着 axis=1 轴的最大值与最小值之差,即 3-1=2(当然 6-4=2, 9-7=2,即第三列与第一列的 ptp 差均为 2)。
3.3.统计数组的百分位数 percentile().

import numpy as np
a=np.array([[1,2,3],[4,5,6],[7,8,9]])
print(np.percentile(a,50))
print(np.percentile(a,50,axis=0))
print(np.percentile(a,50,axis=1))

percentile() 代表着第 p 个百分位数,这里 p 的取值范围是 0-100,如果 p=0,那么就是求最小值,如果 p=50 就是求平均值,如果 p=100 就是求最大值。同样你也可以求得在 axis=0 和 axis=1 两个轴上的 p% 的百分位数。
3.4.统计数组中的中位数 median()、平均数 mean().

import numpy as np
a=np.array([[1,2,3],[4,5,6],[7,8,9]])
#求中位数
print(np.median(a))
print(np.median(a,axis=0))
print(np.median(a,axis=1))
#求平均数
print(np.mean(a))
print(np.mean(a,axis=0))
print(np.mean(a,axis=1))

3.5.统计数组中的加权平均值 average().

import numpy as np
a=np.array([1,2,3,4])
wts=np.array([1,2,3,4])
print(np.average(a))
print(np.average(a,weights=wts))

average() 函数可以求加权平均,加权平均的意思就是每个元素可以设置个权重,默认情况下每个元素的权重是相同的,所以 np.average(a)=(1+2+3+4)/4=2.5,你也可以指定权重数组 wts=[1,2,3,4],这样加权平均 np.average(a,weights=wts)=(11+22+33+44)/(1+2+3+4)=3.0。
3.6.统计数组中的标准差 std()、方差 var().

import numpy as np
a=np.array([1,2,3,4])
print(np.std(a))
print(np.var(a))

方差的计算是指每个数值与平均值之差的平方值的平均数,即 mean((x - x.mean())** 2)。标准差是方差的算术平方根。在数学意义上,代表的是一组数据离平均值的分散程度。所以 np.var(a)=1.25, np.std(a)=1.118033988749895。

4.NumPy 排序.
排序是算法中使用频率最高的一种,也是在数据分析工作中常用的方法.
那么这些排序算法在 NumPy 中实现起来其实非常简单。这里你可以使用 sort 函数,sort(a, axis=-1, kind=‘quicksort’, order=None),默认情况下使用的是快速排序;在 kind 里,可以指定 quicksort、mergesort、heapsort 分别表示快速排序、合并排序、堆排序。同样 axis 默认是 -1,即沿着数组的最后一个轴进行排序,也可以取不同的 axis 轴,或者 axis=None 代表采用扁平化的方式作为一个向量进行排序。另外 order 字段,对于结构化的数组可以指定按照某个字段进行排序。

import numpy as np
a=np.array([[4,3,2],[2,4,1]])
print(np.sort(a))
print(np.sort(a,axis=None))
print(np.sort(a,axis=0))
print(np.sort(a,axis=1))

作业:
练习题:统计全班的成绩假设一个团队里有 5 名学员,成绩如下表所示。你可以用 NumPy 统计下这些人在语文、英语、数学中的平均成绩、最小成绩、最大成绩、方差、标准差。然后把这些人的总成绩排序,得出名次进行成绩输出。
解答一:

# -*- coding:utf-8 -*-
import numpy as np
persontype=np.dtype({
"names":["name","Chinese","English","math"],
"formats":["S32","f","f","f"]
})
peoples=np.array([("张飞".encode('utf-8'),66,65,30),
("关羽".encode('utf-8'),95,85,98),
("赵云".encode('utf-8'),93,92,96),
("黄忠".encode('utf-8'),90,88,77),
("典韦".encode('utf-8'),80,90,90)],
dtype=persontype)
chineses=peoples[:]['Chinese']
englishs=peoples[:]['English']
maths=peoples[:]['math']
#grades=np.array([chineses,englishs,maths])
#ch=np.array(chineses)
#平均成绩
print(np.mean(chineses))
print(np.mean(englishs))
print(np.mean(maths))
#最小成绩
print(np.amin(chineses))
print(np.amin(englishs))
print(np.amin(maths))
#最大成绩
print(np.amax(chineses))
print(np.amax(englishs))
print(np.amax(maths))
#方差
print(np.std(chineses))
print(np.std(englishs))
print(np.std(maths))
#标准差
print(np.var(chineses))
print(np.var(englishs))
print(np.var(maths))
#总成绩排序
print(np.sort(chineses+englishs+maths))
#按姓名排序
print(np.sort(peoples,order='name'))
#姓名排序输出不是中文,如何解决?

解答二:

#简易学生成绩档案管理
import numpy as np
student_type = np.dtype({'names':['studentname','Chinese','English','Math','Total'],'formats':['U10','i','i','i','f']})
students = np.array([ ("张飞",66,65,30,None),("关羽",95,85,98,None),("赵云",93,92,96,None),("黄忠",90,88,77,None),("典韦",80,90,90,None)]
                    ,dtype = student_type)
Chinese = students[:]['Chinese']
English = students[:]['English']
Math = students[:]['Math']
#指标分析
score_analy={'平均成绩':{'语文':np.mean(Chinese),'英语': np.mean(English),'数学':np.mean(Math)}
            ,'最小成绩':{'语文':np.amin(Chinese),'英语': np.amin(English),'数学':np.amin(Math)}
            ,'最大成绩':{'语文':np.amax(Chinese),'英语': np.amax(English),'数学':np.amax(Math)}
            ,'标准差' :{'语文':np.std(Chinese) ,'英语': np.std(English) ,'数学': np.std(Math)}
            ,'方差' :{'语文':np.var(Chinese) ,'英语': np.var(English) ,'数学': np.var(Math)}}
#统计总成绩
for i in range(len(students)):
    students[i]['Total'] = sum(list(students[i])[1:-1])
#输出分析指标
print(" 指标项 \t\t 语文 \t\t 英语 \t\t 数学 ")
print(("-" * 10 +"\t\t")*4)
for index in score_analy:
    report = f"{index:10}".format(index) + "\t\t{语文:>10.2f}\t\t{英语:>10.2f}\t\t{数学:>10.2f}"
    print(report.format_map(score_analy[index]))
print(("-" * 82))
#按总成绩输出排名
print("名次\t\t姓名\t\t总分")
print(("-" * 4 +"\t\t")*3) 
s = np.sort(students,order='Total')
for i in range(len(s)):
    k=-1 * (i+1)
    print('{rank:4}\t\t{name:4}\t\t{score:>4}'.format(rank=i+1,name=s[k]['studentname'],score=s[k]['Total']))

问题.
1.python37如何修改默认编码?
在python安装目录中F:\Python37\Lib\site-packages下,新增文件sitecustomize.py,输入如下代码,重新打开python解释器,运行程序即可.

import sys,imp
imp.reload(sys)
sys.setdefaultencoding('utf-8')

2.如果方法1不行,那就直接在代码中转码.如:
“张飞”.encode(‘utf-8’)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值