用NumPy快速处理数据(学习笔记)

Python科学计算:用NumPy快速处理数据(学习笔记)

前言

此笔记是清华大学计算机博士陈旸《数据分析45讲》的一课内容。由于Numpy的内容比较基础,做了一些记录。
链接:https://time.geekbang.org/column/intro/147

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all'

Python 中一个非常重要的第三方库 NumPy。它不仅是 Python 中使用最多的第三方库,而且还是 SciPy、Pandas 等数据科学的基础库。它所提供的数据结构比 Python 自身的“更高级、更高效”,可以这么说,NumPy 所提供的数据结构是 Python 数据分析的基础。

Python 数组结构中的列表 list,它实际上相当于一个数组的结构。而 NumPy 中一个关键数据类型就是关于数组的,那为什么还存在这样一个第三方的数组结构呢?

实际上,标准的 Python 中,用列表 list 保存数组的数值。由于列表中的元素可以是任意的对象,所以列表中 list 保存的是对象的指针。虽然在 Python 编程中隐去了指针的概念,但是数组有指针,Python 的列表 list 其实就是数组。

使用 NumPy 让你的 Python 科学计算更高效

为什么要用 NumPy 数组结构而不是 Python 本身的列表 list?这是因为列表 list 的元素在系统内存中是分散存储的,而 NumPy 数组存储在一个均匀连续的内存块中。这样数组计算遍历所有的元素,不像列表 list 还需要对内存地址进行查找,从而节省了计算资源。

另外在内存访问模式中,缓存会直接把字节块从 RAM 加载到 CPU 寄存器中。因为数据连续的存储在内存中,NumPy 直接利用现代 CPU 的矢量化指令计算,加载寄存器中的多个连续浮点数。另外 NumPy 中的矩阵计算可以采用多线程的方式,充分利用多核 CPU 计算资源,大大提升了计算效率。

当然除了使用 NumPy 外,你还需要一些技巧来提升内存和提高计算资源的利用率。一个重要的规则就是:避免采用隐式拷贝,而是采用就地操作的方式。举个例子,如果我想让一个数值 x 是原来的两倍,可以直接写成 x*=2,而不要写成 y=x*2。

在 NumPy 里有两个重要的对象:ndarray(N-dimensional array object)解决了多维数组问题,而 ufunc(universal function object)则是解决对数组进行处理的函数。

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)
print (b.shape)
print (a.dtype)
print (b)
(3,)
(3, 3)
int32
[[ 1  2  3]
 [ 4 10  6]
 [ 7  8  9]]
结构数组
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))
28.25
77.5
93.25
93.75
persontype 
dtype([('name', 'S32'), ('age', '<i4'), ('chinese', '<i4'), ('math', '<i4'), ('english', '<f4')])
peoples['age']
array([32, 24, 28, 29], dtype=int32)

ufunc 运算

ufunc 是 universal function 的缩写,是不是听起来就感觉功能非常强大?确如其名,它能对数组中每个元素进行函数操作。NumPy 中很多 ufunc 函数计算速度非常快,因为都是采用 C 语言实现的。

连续数组的创建

NumPy 可以很方便地创建连续数组,比如我使用 arange 或 linspace 函数进行创建:


x1 = np.arange(1,11,2)
x2 = np.linspace(1,9,5)
x1
array([1, 3, 5, 7, 9])
x2
array([1., 3., 5., 7., 9.])

arange() 类似内置函数 range(),通过指定初始值、终值、步长来创建等差数列的一维数组,默认是不包括终值的。

linspace 是 linear space 的缩写,代表线性等分向量的含义。linspace() 通过指定初始值、终值、元素个数来创建等差数列的一维数组,默认是包括终值的。

算数运算

通过 NumPy 可以自由地创建等差数组,同时也可以进行加、减、乘、除、求 n 次方和取余数。


x1 = np.arange(1,11,2)
x2 = np.linspace(1,9,5)
print (np.add(x1, x2))
print (np.subtract(x1, x2))
print (np.multiply(x1, x2))
print (np.divide(x1, x2))
print (np.power(x1, x2))
print (np.remainder(x1, x2))
[ 2.  6. 10. 14. 18.]
[0. 0. 0. 0. 0.]
[ 1.  9. 25. 49. 81.]
[1. 1. 1. 1. 1.]
[1.00000000e+00 2.70000000e+01 3.12500000e+03 8.23543000e+05
 3.87420489e+08]
[0. 0. 0. 0. 0.]
统计函数

如果你想要对一堆数据有更清晰的认识,就需要对这些数据进行描述性的统计分析,比如了解这些数据中的最大值、最小值、平均值,是否符合正态分布,方差、标准差多少等等。它们可以让你更清楚地对这组数据有认知

计数组 / 矩阵中的最大值函数 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))
1
[1 2 3]
[1 4 7]
9
[7 8 9]
[3 6 9]
统计最大值与最小值之差 ptp()

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))
8
[6 6 6]
[2 2 2]
统计数组的百分位数 percentile()

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))
5.0
[4. 5. 6.]
[2. 5. 8.]
统计数组中的中位数 median()、平均数 mean()

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))
5.0
[4. 5. 6.]
[2. 5. 8.]
5.0
[4. 5. 6.]
[2. 5. 8.]
统计数组中的加权平均值 average()

a = np.array([1,2,3,4])
wts = np.array([1,2,3,4])
print (np.average(a))
print (np.average(a,weights=wts))
2.5
3.0
统计数组中的标准差 std()、方差 var()

a = np.array([1,2,3,4])
print (np.std(a))
print (np.var(a))
1.118033988749895
1.25

NumPy 排序

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


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))  
[[2 3 4]
 [1 2 4]]
[1 2 2 3 4 4]
[[2 3 1]
 [4 4 2]]
[[2 3 4]
 [1 2 4]]

总结

在 NumPy 学习中,你重点要掌握的就是对数组的使用,因为这是 NumPy 和标准 Python 最大的区别。在 NumPy 中重新对数组进行了定义,同时提供了算术和统计运算,你也可以使用 NumPy 自带的排序功能,一句话就搞定各种排序算法。

当然要理解 NumPy 提供的数据结构为什么比 Python 自身的“更高级、更高效”,要从对数据指针的引用角度进行理解。

练习题:统计全班的成绩

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

【参考解答】

#!/usr/bin/python
#vim: set fileencoding:utf-8
import numpy as np
scoretype = np.dtype({
    'names': ['name', 'chinese', 'english', 'math'],
    'formats': ['S32', 'i', 'i', 'i']})

peoples = np.array(
        [
            ("zhangfei", 66, 65, 30),
            ("guanyu", 95, 85, 98),
            ("zhaoyun", 93, 92, 96),
            ("huangzhong", 90, 88, 77),
            ("dianwei", 80, 90, 90)
        ], dtype=scoretype)
peoples
array([(b'zhangfei', 66, 65, 30), (b'guanyu', 95, 85, 98),
       (b'zhaoyun', 93, 92, 96), (b'huangzhong', 90, 88, 77),
       (b'dianwei', 80, 90, 90)],
      dtype=[('name', 'S32'), ('chinese', '<i4'), ('english', '<i4'), ('math', '<i4')])
#指定的竖列
name = peoples[:]['name']
chinese = peoples[:]['chinese']
english = peoples[:]['english']
math = peoples[:]['math']
#定义函数用于显示每一排的内容
def show(name,cj):
    print('{} | {} | {} | {} | {} | {} '
          .format(name,np.mean(cj),np.min(cj),np.max(cj),np.var(cj),np.std(cj)))

print("科目 | 平均成绩 | 最小成绩 | 最大成绩 | 方差 | 标准差")
show("语文", chinese)
show("英语", english)
show("数学", math)

print("排名:")
#用sorted函数进行排序
ranking = sorted(peoples,key=lambda x:x[1]+x[2]+x[3], reverse=True)
print(ranking)
科目 | 平均成绩 | 最小成绩 | 最大成绩 | 方差 | 标准差
语文 | 84.8 | 66 | 95 | 114.96000000000001 | 10.721940122944169 
英语 | 84.0 | 65 | 92 | 95.6 | 9.777525249264253 
数学 | 78.2 | 30 | 98 | 634.56 | 25.19047439013406 
排名:
[(b'zhaoyun', 93, 92, 96), (b'guanyu', 95, 85, 98), (b'dianwei', 80, 90, 90), (b'huangzhong', 90, 88, 77), (b'zhangfei', 66, 65, 30)]

【参考】Python3 sorted() 函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值