位置与切片,现在扩展到多个维度
数组的索引与列表一样:a[0] 是第一个元素,a[-1] 是最后一个,a[start:stop:step] 是在 stop 之前停止的切片。不同之处在于数组可以有多个维度,你要为每个维度各给一个索引或切片,用逗号隔开:m[行, 列]。单独的 : 表示“这一维的全部”,所以 m[:, 1] 是整个第二列,m[1](或 m[1, :])是整个第二行。负数从末尾数起,步长 -1 表示反向。
import numpy as np
a = np.array([10., 11., 12., 13., 14., 15.])
print(a[0], a[-1]) # 10.0 15.0
print(a[1:4]) # [11. 12. 13.]
print(a[-2:]) # [14. 15.]
print(a[::2]) # [10. 12. 14.]
print(a[::-1]) # [15. 14. 13. 12. 11. 10.]
# Two dimensions: one index or slice per dimension
m = np.arange(12).reshape(3, 4)
print(m[1, 2]) # 6
print(m[:, 1]) # [1 5 9] the whole second column
print(m[-1, :]) # [ 8 9 10 11] the last row
print(m[0:2, 1:3]) # [[1 2]
# [5 6]]切片是视图,不是副本
与列表切片不同,NumPy 的基本切片不会复制数据:它是指向同一块内存的视图,因此通过它写入会改动原数组。这使得即使对巨大的数组切片也是瞬间完成,但也常让人意外:part = a[1:4]; part[0] = 99 也会改变 a[1]。需要独立数组时调用 .copy()。可以用 np.shares_memory(a, b) 检查。行、列、步长和反向切片都有同样的视图行为。
import numpy as np
a = np.array([10., 11., 12., 13., 14., 15.])
part = a[1:4] # a view, no data copied
part[0] = 99
print(a) # [10. 99. 12. 13. 14. 15.] a changed too
safe = a[1:4].copy() # an independent array
safe[0] = -1
print(a) # [10. 99. 12. 13. 14. 15.] unchanged
print(np.shares_memory(a, a[::2])) # True
print(np.shares_memory(a, safe)) # False布尔掩码与索引列表
对数组做比较会得到同样大小的布尔数组:r > 0 在收益为正的位置是 True。把这个掩码用作索引,r[r > 0],就只选出这些元素。条件用 &(与)、|(或)、~(非)组合,每个条件都要加括号,因为 Python 的 and/or 不能用于数组。整数列表或数组也可以,a[[0, 2, 5]] 会按该顺序取出恰好这些位置。用掩码或索引列表选择会复制数据,也可以通过掩码赋值:a[a > 3] = 0。
import numpy as np
r = np.array([0.01, -0.02, 0.03, -0.01, 0.0, 0.02])
print(r > 0) # [ True False True False False True]
print(r[r > 0]) # [0.01 0.03 0.02]
print(r[(r > 0) & (r < 0.025)]) # [0.01 0.02] parentheses are required
print(np.where(r > 0)[0]) # [0 2 5] positions where it holds
# Pick by position, in any order
w = np.array([3.0, 9.0, 1.0, 7.0])
order = np.argsort(-w) # positions from the largest value down
print(order[:2], w[order[:2]]) # [1 3] [9. 7.]
# Assign through a mask
counts = np.array([1, 2, 3, 4, 5, 6])
counts[counts > 3] = 0
print(counts) # [1 2 3 0 0 0]import numpy as np
# Rows are days, columns are assets (AAPL, MSFT, GOOG)
R = np.array([[ 0.02, -0.01, 0.03],
[ 0.01, 0.00, 0.02],
[-0.03, 0.02, -0.01],
[ 0.00, 0.01, 0.04]])
print(R[:, [0, 2]]) # the AAPL and GOOG columns, as a copy
print(R[R[:, 0] > 0]) # the days on which AAPL rose (whole rows)
print(R[R[:, 0] > 0].shape) # (2, 3)
print(R[-2:, 1].mean()) # 0.015 last two days of MSFT知道自己拿到的是视图还是副本基本切片(
a[1:4]、m[:, 1]、a[::2])是视图;掩码和索引列表(a[a > 0]、a[[0, 2]])是副本。返回参数切片的函数,等于给调用者一扇通向其自身数据的窗口,之后的写入可能出乎意料地改动它。要有意识地选择:速度重要且数据只读时返回视图,否则用 .copy()。实验的测试会检查这两种行为。- 每维一个索引或切片:
m[行, 列]、m[:, 1](一列)、m[-1](最后一行)、a[::-1]。 - 基本切片是视图(写入会反映;用
.copy()分离);掩码和索引列表生成副本。 - 掩码:
a[a > 0],用带括号的&、|、~组合;np.argsort给出排序后的位置。
下一节:向量化,用整个数组的运算取代 Python 循环。
实验:评分内容
- 用
last_rows取最近的几行25 分 - 用
positive_values只保留正值25 分 - 用
every_kth每隔 k 个取一个值25 分 - 用
top_k_indices找出最大的 k 个值的位置25 分