numpy数组切片_numpy入门基础

f34ca20fcf6edcbd6b00b8fdd430be9b.png

NumPy之于数值计算特别重要的原因之一,是因为它可以高效处理大数组的数据。

这是因为:

NumPy是在一个连续的内存块中存储数据,独立于其他Python内置对象。

NumPy的C语言编写的算法库可以操作内存,而不必进行类型检查或其它前期

工作。比起Python的内置序列,NumPy数组使用的内存更少。

NumPy可以在整个数组上执行复杂的计算,而不需要Python的for循环。

#要搞明白具体的性能差距,考察一个包含一百万整数的数组,和一个等价的Python列表:
import numpy as np
my_arr = np.arange(1000000)
my_list = list(range(1000000))
#各个序列分别乘以2:
%time for _ in range(10): my_arr2 = my_arr * 2
%time for _ in range(10): my_list2 = [x * 2 for x in my
_list]

756be53835758e3ab88e98350d92db25.png

基于NumPy的算法要比纯Python快40多倍(甚至更快),并且使用的内存更少。

一、NumPy的ndarray:一种多维数组对象

NumPy最重要的一个特点就是其N维数组对象(即ndarray),该对象是一个快速而灵活的大数据集容器。

data = np.random.randn(2, 3)
data
data * 10
data + data
# ndarray是一个通用的同构数据多维容器,也就是说,其中的所有元素必须是相同类型的。
# 每个数组都有一个shape(一个表示各维度大小的元组)和一个dtype(一个用于说明数组数据类型的对象):
data.shape
data.dtype

2d9f817bde32f00595b21209ebc7f9f3.png

1、创建ndarray

创建数组最简单的办法就是使用array函数。它接受一切序列型的对象(包括其他数组),然后产生一个新的含有传入数据的NumPy数组。以一个列表的转换为例:

data1 = [6, 7.5, 8, 0, 1]
arr1 = np.array(data1)
arr1

# 嵌套序列(比如由一组等长列表组成的列表)将会被转换为一个多维数组:
data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2)
arr2

arr2.ndim

arr2.shape

# np.array会尝试为新建的这个数组推断出一个较为合适的数据类型。数据类型保存在一个特殊的dtype对象中。
# 比如说,在上面的两个例子中,我们有:
arr1.dtype

arr2.dtype

d8cfffd6a0ed8ae83f16202829d99662.png

除np.array之外,还有一些函数也可以新建数组。比如,zeros和ones分别可以创建指定长度或形状的全0或全1数组。empty可以创建一个没有任何具体值的数组。要用这些方法创建多维数组,只需传入一个表示形状的元组即可:

np.zeros(10)

np.zeros((3, 6))

np.empty((2, 3, 2))
# 注意:认为np.empty会返回全0数组的想法是不安全的。很多情况下(如前所示),它返回的都是一些未初始化的垃圾值。

# arange是Python内置函数range的数组版:
np.arange(15)

919225fd0f7b6f957976a0bc8c321239.png

下图列出了一些数组创建函数。由于NumPy关注的是数值计算,因此,如果没有特别指定,数据类型基本都是float64(浮点数)。

33cbd0e8de8d835203336d42aa8dc59d.png

2、ndarray的数据类型

dtype(数据类型)是一个特殊的对象,它含有ndarray将一块内存解释为特定数据类型所需的信息:

arr1 = np.array([1, 2, 3], dtype=np.float64)
arr2 = np.array([1, 2, 3], dtype=np.int32)
arr1.dtype

arr2.dtype

552c49db02a213cfd0dea1fb5d866b80.png

数值型dtype的命名方式相同:一个类型名(如float或int),后面跟一个用于表示各元素位长的数字。标准的双精度浮点值(即Python中的float对象)需要占用8字节(即64位)。因此,该类型在NumPy中就记作float64。

下表列出了NumPy所支持的全部数据类型:

64f8f49549284034e2ccce22fa915f9c.png

可以通过ndarray的astype方法明确地将一个数组从一个dtype转换成另一个dtype:

arr = np.array([1, 2, 3, 4, 5])
arr.dtype

float_arr = arr.astype(np.float64)
float_arr.dtype

# 如果将浮点数转换成整数,则小数部分将会被截取删除:
arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
arr.astype(np.int32)

# 如果某字符串数组表示的全是数字,也可以用astype将其转换为数值形式:
numeric_strings = np.array(['1.25', '-9.6', '42'], dtype=np.string_)
numeric_strings.astype(float)
# 使用numpy.string_类型时,一定要小心,因为NumPy的字符串数据是大小固定的,发生截取时,不会发出警告。
# pandas提供了更多非数值数据的便利的处理方法。

# 如果转换过程因为某种原因而失败了(比如某个不能被转换为float64的字符串),就会引发一个ValueError。
# NumPy会将Python类型映射到等价的dtype上。
# 数组的dtype还有另一个属性:
int_array = np.arange(10)
calibers = np.array([.22, .270, .357, .380, .44, .50],dtype=np.float64)
int_array.astype(calibers.dtype)

# 还可以用简洁的类型代码来表示dtype:
empty_uint32 = np.empty(8, dtype='u4')
empty_uint32

a7af96a27b954345ed20f4918af35ef0.png

3、NumPy数组的运算

数组很重要,因为它使你不用编写循环即可对数据执行批量运算。NumPy用户称其为矢量化;

arr = np.array([[1., 2., 3.], [4., 5., 6.]])
arr

arr * arr

arr - arr

# 数组与标量的算术运算会将标量值传播到各个元素:
1 / arr

arr ** 0.5

# 大小相同的数组之间的比较会生成布尔值数组:
arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
arr2

arr2 > arr
# 不同大小的数组之间的运算叫做广播(broadcasting)

ee5766f67208c827bb53fac059e57f93.png

4、基本的索引和切片

arr = np.arange(10)
arr

arr[5]

arr[5:8]

arr[5:8] = 12
arr
# 注意:如果你想要得到的是ndarray切片的一份副本而非视图,就需要明确地进行复制操作,
# 例如 arr[5:8].copy()

# 在一个二维数组中,各索引位置上的元素不再是标量而是一维数组:
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[2]

# 可以传入一个以逗号隔开的索引列表来选取单个元素。也就是说,下面两种方式是等价的:
arr2d[0][2]

arr2d[0, 2]

40d6ad25c3cb346551e473d2eec36b48.png

5、切片索引

ndarray的切片语法跟Python列表这样的一维对象差不多:

# ndarray的切片语法跟Python列表这样的一维对象差不多:
arr

arr[1:6]

# 对于之前的二维数组arr2d,其切片方式稍显不同:
arr2d

arr2d[:2]
# arr2d[:2]可以被认为是“选取arr2d的前两行”

# 你可以一次传入多个切片,就像传入多个索引那样:
arr2d[:2, 1:]
# 像这样进行切片时,只能得到相同维数的数组视图。通过将整数索引和切片混合,可以得到低维度的切片。

arr2d[1, :2]
# 相当于取第2行的前2列

# 还可以选择第三列的前两行:
arr2d[:2, 2]

# 对切片表达式的赋值操作也会被扩散到整个选区:
arr2d[:2, 1:] = 0
arr2d

60fb8b1184583b77ee4479c9e563ae3c.png

6、布尔型索引

假设我们有一个用于存储数据的数组以及一个存储姓名的数组(含有重复项)。在这里,我将使用numpy.random中的randn函数生成一些正态分布的随机数据:

names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will','Joe', 'Joe'])
data = np.random.randn(7, 4)
names

data

# 假设每个名字都对应data数组中的一行,而我们想要选出对应于名字"Bob"的所有行。
# 跟算术运算一样,数组的比较运算(如==)也是矢量化的。因此,对names和字符串"Bob"的比较运算将会产生一个布尔型数组:
names == 'Bob'

# 这个布尔型数组可用于数组索引:
data[names == 'Bob']
# 布尔型数组的长度必须跟被索引的轴长度一致;
# 注意:如果布尔型数组的长度不对,布尔型选择就会出错,因此一定要小心;

# 选取了 names == 'Bob' 的行,并索引了列:
data[names == 'Bob', 2:]

data[names == 'Bob', 3]

# 要选择除"Bob"以外的其他值,既可以使用不等于符号(!=),也可以通过~对条件进行否定:
names != 'Bob'

data[~(names == 'Bob')]
# ~操作符用来反转条件很好用:

cond = names == 'Bob'
data[~cond]

# 选取这三个名字中的两个需要组合应用多个布尔条件,使用&(和)、|(或)之类的布尔算术运算符即可:
# 注意:Python关键字and和or在布尔型数组中无效。要使用&与|。
mask = (names == 'Bob') | (names == 'Will')
mask

data[mask]

# 通过布尔型数组设置值是一种经常用到的手段。为了将data中的所有负值都设置为0,我们只需:
data[data < 0] = 0
data

# 通过一维布尔数组设置整行或列的值也很简单:
data[names != 'Joe'] = 7
data

b956f4d6bf15ba2b9926d6cb333c6e9f.png

91af227d4f3f027b469f3af9b12ef993.png

b9ca003a97c0f2896d08a87096a6411f.png

7、数组转置和轴对换

转置是重塑的一种特殊形式,它返回的是源数据的视图(不会进行任何复制操作)。数组不仅有transpose方法,还有一个特殊的T属性:

arr = np.arange(15).reshape((3, 5))
arr

arr.T

# 在进行矩阵计算时,经常需要用到该操作,比如利用np.dot计算矩阵内积:
arr = np.random.randn(6, 3)
arr

np.dot(arr.T, arr)

ddcefa2e174fa5147901f3b7807df300.png

二、通用函数:快速的元素级数组函数

arr = np.arange(10)
arr

np.sqrt(arr)

np.exp(arr)

# 这些都是一元(unary)ufunc。
# 另外一些(如add或maximum)接受2个数组(因此也叫二元(binary)ufunc),并返回一个结果数组:
x = np.random.randn(8)
y = np.random.randn(8)
x

y

np.maximum(x, y)
# numpy.maximum计算了x和y中元素级别最大的元素。

# modf就是Python内置函数divmod的矢量化版本,它会返回浮点数数组的小数和整数部分:
arr = np.random.randn(7) * 5
arr

remainder, whole_part = np.modf(arr)
remainder

whole_part

be3d7d75a996b97233eae5432e0387c5.png

b16bd83d8eed7f0d52aeaec764b84701.png

下面分别列出了一些一元和二元ufunc:

一元ufunc:

63528ee3de1c40bcd081efdb729564d3.png

21cc0a03f5b31d0b0a1ff902c62890b3.png

二元ufunc():

d6853f51434cdfb2f90386b66dcda61e.png

三、利用数组进行数据处理

NumPy数组使你可以将许多种数据处理任务表述为简洁的数组表达式(否则需要编写循环)。用数组表达式代替循环的做法,通常被称为矢量化。一般来说,矢量化数组运算要比等价的纯Python方式快上一两个数量级(甚至更多),尤其是各种数值计算。

# 计算函数 sqrt(x^2+y^2) 。
# np.meshgrid函数接受两个一维数组,并产生两个二维矩阵(对应于两个数组中所有的(x,y)对)
points = np.arange(-5, 5, 0.01) # 1000 equally spacedpoints
xs, ys = np.meshgrid(points, points)
ys

z = np.sqrt(xs ** 2 + ys ** 2)
z

b7c02f2f17ed989f798ac4313276f0f0.png

1、将条件逻辑表述为数组运算

# numpy.where函数是三元表达式x if condition else y的矢量化版本;
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
# 根据cond中的值选取xarr和yarr的值:当cond中的值为True时,选取xarr的值,否则从yarr中选取;
result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)]
result

# 这有几个问题。
# 第一,它对大数组的处理速度不是很快(因为所有工作都是由纯Python完成的);
# 第二,无法用于多维数组。若使用np.where,则可以将该功能写得非常简洁:
result = np.where(cond, xarr, yarr)
result
# np.where的第二个和第三个参数不必是数组,它们都可以是标量值;
# 在数据分析工作中,where通常用于根据另一个数组而产生一个新的数组;

# 有一个由随机数据组成的矩阵,你希望将所有正值替换为2,将所有负值替换为-2。若利用np.where,则
arr = np.random.randn(4, 4)
arr

arr > 0

np.where(arr > 0, 2, -2)

# 使用np.where,可以将标量和数组结合起来。可用常数2替换arr中所有正的值:
np.where(arr > 0, 2, arr) # set only positive values to 2
# 传递给where的数组大小可以不相等,甚至可以是标量值。

ddee0ad6d5b85a008db8c5e03f23a98c.png

2、数学和统计方法

arr = np.random.randn(5, 4)
arr

arr.mean()

np.mean(arr)

arr.sum()

# mean和sum这类的函数可以接受一个axis选项参数,用于计算该轴向上的统计值,最终结果是一个少一维的数组:
# arr.mean(1)是“计算行的平均值”;
arr.mean(axis=1)

# arr.sum(0)是“计算每列的和”;
arr.sum(axis=0)

# cumsum(累加函数)和cumprod(累积)之类的方法则不聚合,而是产生一个由中间结果组成的数组:
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
arr.cumsum()

# 多维数组中,累加函数(如cumsum)返回的是同样大小的数组;
arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr

arr.cumsum(axis=0)

arr.cumprod(axis=1)

cb762769306326f3bcee3414d6f77857.png

9eccb007fdd7a83674144df0fd67dc7b.png

下表是基本数组统计方法:

ecb563b25bbbcdc359230fae5fd7ad57.png

da117066742c8548a028b91dae83c5a5.png

3、用于布尔型数组的方法

# 在数组统计方法中,布尔值会被强制转换为1(True)和0(False);
# 因此,sum经常被用来对布尔型数组中的True值计数:
arr = np.random.randn(100)
(arr > 0).sum()

# 另外还有两个方法any和all,它们对布尔型数组非常有用。
# any用于测试数组中是否存在一个或多个True,而all则检查数组中所有值是否都是True:
bools = np.array([False, False, True, False])
bools.any()

bools.all()

ecbbbda6b1432efd26f36286855642f2.png

4、排序

# 跟Python内置的列表类型一样,NumPy数组也可以通过sort方法就地排序:
arr = np.random.randn(6)
arr

arr.sort()
arr

# 多维数组可以在任何一个轴向上进行排序,只需将轴编号传给sort即可:
arr = np.random.randn(5, 3)
arr

arr.sort(1)
arr

2a321a4888291c2f41e25b4e05dc8676.png

5、唯一化以及其它的集合逻辑

# NumPy提供了一些针对一维ndarray的基本集合运算。
# 最常用的可能要数np.unique了,它用于找出数组中的唯一值并返回已排序的结果:
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will','Joe', 'Joe'])
np.unique(names)

ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
np.unique(ints)

# 和np.unique等价的纯Python代码来对比:
sorted(set(names))

# 函数np.in1d用于测试一个数组中的值在另一个数组中的成员资格,返回一个布尔型数组:
values = np.array([6, 0, 0, 3, 2, 5, 6])
np.in1d(values, [2, 3, 6])

4de558dc3010e09a64d520bab53d3e74.png

NumPy中的集合函数:

b39281d07d6e88b55052024b13071886.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值