Numpy的基础用法

  1. # 高效提取相应切片的索引方法(Indexing)
  2. '''
  3. [[1 2 3]
  4. [4 5 6]
  5. [7 8 9]]
  6. '''
  7. x = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  8. print(x[:, 0]) # 将会输出 [1 4 7]
  9. print(x[:, 1]) # 将会输出 [2 5 8]
  10. print(x[2, :]) # 将会输出 [7 8 9]
  11. print(x[:2, 0]) # 将会输出 [1 4]
  12. print(x[1, :2]) # 将会输出 [4 5]
  13. print(x[:2, :2]) # 将会输出 [[1 2], [4 5]]
  14. # 初始化为全0、全1、随机等
  15. x1 = np.zeros((3, 3)) # 建立3x3的全0矩阵
  16. print(x1)
  17. x2 = np.ones((3, 3)) # 建立3x3的全1矩阵
  18. print(x2)
  19. x3 = np.random.random((3, 3)) # 建立3x3的随机矩阵(0到1之间均匀分布)
  20. print(x3)
  21. # Numpy数组的加、减、乘、除
  22. x = np.array([[1, 2], [3, 4]])
  23. y = np.array([[4, 3], [2, 1]])
  24. # Numpy加法
  25. print(x + y) # 将会输出[[5, 5], [5, 5]]
  26. # Numpy减法
  27. print(x - y) # 将会输出[[-3, -1], [1, 3]]
  28. # Numpy乘法
  29. print(x * y) # element-wise乘法,将会输出[[4, 6], [6, 4]]
  30. print(np.dot(x, y)) # 矩阵乘法,将会输出[[8, 5], [20, 13]]
  31. # Numpy除法
  32. print(x / y) # 将会输出[[0.25, 2/3], [1.5, 4]]
  33. # Numpy支持一些列对高维数组的数学运算操作
  34. # 对每个元素取e的指数
  35. print(np.exp(x)) # 将会输出[[e^1, e^2], [e^3, e^4]]
  36. # 对每个元素取根号
  37. print(np.sqrt(x)) # 将会输出[[1, 根号2], [根号3, 2]]
  38. # 对第一个axis取平均值
  39. print(np.average(x, axis = 0)) # 将会输出[2, 3]
  40. # 对第二个axis取平均值
  41. print(np.average(x, axis = 1)) # 将会输出[1.5, 3.5]
'''
axis概念解释:不同的axis可以视为不同深度的for循环所对应的数据:
1、第一个axis对应着第一层for循环所能达到的数据;
2、第二个axis对应着第二层for循环所能达到的数据;
n、第n个axis对应着第n层for循环所能达到的数据。
'''
x = np.array([[1, 2], [3, 4]])
print(x)

# 对第一个axis取平均值
print(np.average(x, axis = 0))  # 将会输出[2, 3]
# 对第二个axis取平均值
print(np.average(x, axis = 1))  # 将会输出[1.5, 3.5]

# axis = 0 的等价描述
result = np.zeros(2)
for elem in x:
    result += elem
print(result / 2)

# axis = 1 的等价描述
result = np.zeros(2)
idx = 0
for row in x:
    for elem in row:
        result[idx] += elem
    idx += 1
print(result / 2)

4.1 Numpy入门 - 图1

算法的向量化与“升维”

'''
算法向量化与“升维”两点思想:
1、将for循环替换成Numpy运算;
2、将难以直接向量化的算法所对应的数组进行“升维”;
'''
import time


# 第一点是向量化思维的基石
x = np.random.random((1000, 1000))
ans = np.zeros((1000, 1000))

# 目的:计算 x + 1 并将结果存进ans中
# 编写繁琐、效率低下的for循环写法
t = time.time()
for i, row in enumerate(x):
    for j, elem in enumerate(row):
        ans[i][j] = elem + 1
t = time.time() - t
print(t)

# 利用Numpy运算直接进行实现
t = time.time()
ans = x + 1
t = time.time() - t
print(t)

# 更快、更省内存的写法
t = time.time()
np.add(x, 1, ans)
t = time.time() - t
print(t)


# 第二点是对广播(Broadcasting)的高级应用,利用Broadcasting来将某一段重复的运算进行向量化

x = np.array([1, 2, 3])
y = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])
z = y - x
print(z)

# 方式一:利用Numpy自带的函数——np.tile
x = y = np.array([1, 2, 3])
y = np.tile(y, [3, 1]).T        # 此时y变为 [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
z = y - x
print(z)

# 方式二:利用Numpy的Broadcasting进行“升维”运算
# y“宽度”为1,x“宽度”为3,Numpy的Broadcasting内部对y隐性进行“扩张”以“适配”x的宽度
x = y = np.array([1, 2, 3])
z = y[:, None] - x
print(z)

高效应用Numpy的一个思想

使用Numpy时,应该尽量避免不必要的拷贝。
比如:
计算ans = x + 1时,最快的实现方式是np.add(x, 1, ans)

  • 对于np.add(x, 1, ans),在计算x+1时会将结果直接写进ans;
  • 对于ans = x + 1, 会将x+1的结果放进内存,再把内存中的结果赋值给ans。

建议:

  • x = x + 1(建议使用x+=1);
  • y = x.flatten()(建议使用y = x.ravel());
  • x = x.T(无替换方案,不过我们要尽量少用转置)

在觉得程序运行不如想象中的高效时,检查是否引发了不必要的拷贝时一个重要的应用思想。